Как перестать поддерживать ее, при выполнении клиентского кода в ходе динамической трансляции.
#if defined(TARGET_XARCH)
#if defined(TARGET_X86)
/*
REGDEF(name, rnum, mask, sname) */
REGDEF(EAX, 0, 0x01, "eax" )
REGDEF(ECX, 1, 0x02, "ecx" )
REGDEF(EDX, 2, 0x04, "edx" )
REGDEF(EBX, 3, 0x08, "ebx" )
REGDEF(ESP, 4, 0x10, "esp" )
REGDEF(EBP, 5, 0x20, "ebp" )
REGDEF(ESI, 6, 0x40, "esi" )
REGDEF(EDI, 7, 0x80, "edi" )
REGALIAS(RAX, EAX)
REGALIAS(RCX, ECX)
REGALIAS(RDX, EDX)
REGALIAS(RBX, EBX)
REGALIAS(RSP, ESP)
REGALIAS(RBP, EBP)
REGALIAS(RSI, ESI)
REGALIAS(RDI, EDI)
#else // !defined(TARGET_X86)
/*
REGDEF(name, rnum, mask, sname) */
REGDEF(RAX, 0, 0x0001, "rax" )
REGDEF(RCX, 1, 0x0002, "rcx" )
REGDEF(RDX, 2, 0x0004, "rdx" )
REGDEF(RBX, 3, 0x0008, "rbx" )
REGDEF(RSP, 4, 0x0010, "rsp" )
REGDEF(RBP, 5, 0x0020, "rbp" )
REGDEF(RSI, 6, 0x0040, "rsi" )
REGDEF(RDI, 7, 0x0080, "rdi" )
REGDEF(R8, 8, 0x0100, "r8" )
REGDEF(R9, 9, 0x0200, "r9" )
REGDEF(R10, 10, 0x0400, "r10" )
REGDEF(R11, 11, 0x0800, "r11" )
REGDEF(R12, 12, 0x1000, "r12" )
REGDEF(R13, 13, 0x2000, "r13" )
REGDEF(R14, 14, 0x4000, "r14" )
REGDEF(R15, 15, 0x8000, "r15" )
REGALIAS(EAX, RAX)
REGALIAS(ECX, RCX)
REGALIAS(EDX, RDX)
REGALIAS(EBX, RBX)
REGALIAS(ESP, RSP)
REGALIAS(EBP, RBP)
REGALIAS(ESI, RSI)
REGALIAS(EDI, RDI)
#endif // !defined(TARGET_X86)
// Кодогенератор
void CodeGen::genCodeForBinary(GenTreeOp* treeNode)
{
GenTree* op1 = treeNode->gtGetOp1();
GenTree* op2 = treeNode->gtGetOp2();
instruction ins = genGetInsForOper(treeNode->OperGet(), targetType);
regNumber op1reg = op1->isUsedFromReg() ? op1->GetRegNum() : REG_NA;
regNumber op2reg = op2->isUsedFromReg() ? op2->GetRegNum() : REG_NA;
GenTree* dst;
GenTree* src;
// This is the case of reg1 = reg1 op reg2
// We're ready to emit the instruction without any moves
if (op1reg == targetReg)
{
dst = op1;
src = op2;
}
// We have reg1 = reg2 op reg1
// In order for this operation to be correct
// we need that op is a commutative operation so
// we can convert it into reg1 = reg1 op reg2 and emit
// the same code as above
else if (op2reg == targetReg)
{
dst = op2;
src = op1;
}
// dest, op1 and op2 registers are different:
// reg3 = reg1 op reg2
// We can implement this by issuing a mov:
// reg3 = reg1
// reg3 = reg3 op reg2
else
{
var_types op1Type = op1->TypeGet();
inst_Mov(op1Type, targetReg, op1reg, /* canSkip */ false);
regSet.verifyRegUsed(targetReg);
gcInfo.gcMarkRegPtrVal(targetReg, op1Type);
dst = treeNode;
src = op2;
}
// try to use an inc or dec
if (oper == GT_ADD && !varTypeIsFloating(treeNode) && src->isContainedIntOrIImmed() && !treeNode->gtOverflowEx())
{
if (src->IsIntegralConst(1))
{
emit->emitIns_R(INS_inc, emitTypeSize(treeNode), targetReg);
genProduceReg(treeNode);
return;
}
else if (src->IsIntegralConst(-1))
{
emit->emitIns_R(INS_dec, emitTypeSize(treeNode), targetReg);
genProduceReg(treeNode);
return;
}
}
regNumber r = emit->emitInsBinary(ins, emitTypeSize(treeNode), dst, src);
}
// Эммитер
/*****************************************************************************
*
* Add an instruction with two register operands.
*/
void emitter::emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, insOpts instOptions)
{
if (IsMovInstruction(ins))
{
assert(!"Please use emitIns_Mov() to correctly handle move elision");
emitIns_Mov(ins, attr, reg1, reg2, /* canSkip */ false);
}
emitAttr size = EA_SIZE(attr);
assert(size <= EA_64BYTE);
noway_assert(emitVerifyEncodable(ins, size, reg1, reg2));
/* Special case: "XCHG" uses a different format */
insFormat fmt = (ins == INS_xchg) ? IF_RRW_RRW : emitInsModeFormat(ins, IF_RRD_RRD);
instrDesc* id = emitNewInstrSmall(attr);
id->idIns(ins);
id->idInsFmt(fmt);
id->idReg1(reg1);
id->idReg2(reg2);
if ((instOptions & INS_OPTS_EVEX_b_MASK) != INS_OPTS_NONE)
{
// if EVEX.b needs to be set in this path, then it should be embedded rounding.
assert(UseEvexEncoding());
id->idSetEvexbContext(instOptions);
}
UNATIVE_OFFSET sz = emitInsSizeRR(id);
id->idCodeSize(sz);
dispIns(id);
emitCurIGsize += sz;
}
Почему программы с одних адресов начинаются?
Вот есть Tlb, представим это как линейный массив, или c , если все адреса будут одинаковы. То Очевидно что tlb будет работать в 1% своего множества
// Initialize ILGPU.
Context context = Context.CreateDefault();
Accelerator accelerator = context.CreateCLAccelerator(1);//context.GetPreferredDevice(preferCPU: false) .CreateAccelerator(context);
// Load the data.
using MemoryBuffer1D<float, Stride1D.Dense> deviceData = accelerator.Allocate1D(input);
using MemoryBuffer1D<float, Stride1D.Dense> deviceOutput = accelerator.Allocate1D<float>(output);
// load / precompile the kernel
Action<Index1D, ArrayView<float>, ArrayView<float>> loadedKernel =
accelerator.LoadAutoGroupedStreamKernel<Index1D, ArrayView<float>, ArrayView<float>>(Kernel);
// finish compiling and tell the accelerator to start computing the kernel
loadedKernel((int)deviceOutput.Length, deviceData.View, deviceOutput.View);
accelerator.Synchronize();
Setup
метод. Раз уж ты пользуешься BenchmarkDotNet, то вот помощь с этимpublic class SampleBenchmark
{
static void Kernel(Index1D i, ArrayView<float> data, ArrayView<float> output)
{
output[i] = data[i % data.Length];
}
public static IEnumerable<object[]> Arguments => new[] {new object[]{new float[1000000], new float[1000000]} };
private float[] _outputBuffer = new float[1000000];
private float[] _inputBuffer = new float[1000000];
private Context? _context;
private Accelerator? _accelerator;
private Action<Index1D, ArrayView<float>, ArrayView<float>>? _loadedKernel;
private MemoryBuffer1D<float, Stride1D.Dense>? _deviceData;
private MemoryBuffer1D<float, Stride1D.Dense>? _deviceOutput;
[GlobalSetup]
public void Setup()
{
var random = new Random();
for (var i = 0; i < _inputBuffer.Length; i++)
{
_inputBuffer[i] = random.NextSingle();
}
_context = Context.CreateDefault();
_accelerator = _context.GetPreferredDevice(preferCPU: false).CreateAccelerator(_context);
_loadedKernel = _accelerator!.LoadAutoGroupedStreamKernel<Index1D, ArrayView<float>, ArrayView<float>>(Kernel);
_deviceData = _accelerator!.Allocate1D(_inputBuffer);
_deviceOutput = _accelerator!.Allocate1D(_outputBuffer);
}
[GlobalCleanup]
public void TearDown()
{
_context?.Dispose();
_accelerator?.Dispose();
_deviceData?.Dispose();
_deviceOutput?.Dispose();
}
[ArgumentsSource(nameof(Arguments))]
[Benchmark]
public void GPUTest(float[] input, float[] output)
{
// finish compiling and tell the accelerator to start computing the kernel
_loadedKernel!((int)_deviceOutput.Length, _deviceData.View, _deviceOutput.View);
_accelerator!.Synchronize();
}
[Benchmark]
[ArgumentsSource(nameof(Arguments))]
public void CpuTest(float[] input, float[] output)
{
for (var i = 0; i < input.Length; i++)
{
output[i] = input[i];
}
}
}
| Method | input | output | Mean | Error | StdDev |
|-------- |---------------- |---------------- |----------:|---------:|---------:|
| GPUTest | Single[1000000] | Single[1000000] | 61.18 us | 0.101 us | 0.095 us |
| CpuTest | Single[1000000] | Single[1000000] | 243.54 us | 3.114 us | 2.600 us |
var typeToFunc = new Dictionary<Type, AddFunc>() {{typeof(int), IntAdd}, {typeof(Vector2), Vector2Add}};
var left = 123;
var right = 14455;
var result = Add(left, right);
Console.WriteLine($"Результат сложения {left} и {right} = {result}");
var leftVector = new Vector2(123, 55);
var rightVector = new Vector2(55, 111);
var resultVector = Add(leftVector, rightVector);
Console.WriteLine($"Результат сложения {leftVector} и {rightVector} = {resultVector}");
T Add<T>(T left, T right)
{
return ( T ) typeToFunc[typeof(T)](left, right);
}
object Vector2Add(object left, object right)
{
return ( Vector2 ) left + ( Vector2 ) right;
}
object IntAdd(object left, object right)
{
return (int) left + (int) right;
}
delegate object AddFunc(object left, object right);
var number = NumberOrVector2<int>.FromNumber(123);
var newNumber = number.Add(() => 23, () => throw new InvalidOperationException("хранится число"));
if (newNumber.TryGetNumber(out var result))
{
Console.WriteLine($"Получился результат: {result}");
}
else
{
Console.WriteLine($"Ошибка - хранился вектор");
}
public readonly struct NumberOrVector2<TNumber> where TNumber: unmanaged, INumber<TNumber>
{
private readonly TNumber _number;
private readonly Vector2? _vector;
private NumberOrVector2(TNumber number, Vector2? vector)
{
_number = number;
_vector = vector;
}
public bool TryGetNumber(out TNumber number)
{
number = _number;
return !_vector.HasValue;
}
public bool TryGetVector(out Vector2 vector)
{
vector = _vector.GetValueOrDefault();
return _vector.HasValue;
}
public NumberOrVector2<TNumber> Add(Func<TNumber> numberAdd, Func<Vector2> vectorAdd)
{
if (_vector is {} vector)
{
return new NumberOrVector2<TNumber>(_number, vector + vectorAdd());
}
return new NumberOrVector2<TNumber>(_number + numberAdd(), null);
}
public static NumberOrVector2<TNumber> FromNumber(TNumber number)
{
return new NumberOrVector2<TNumber>(number, null);
}
public static NumberOrVector2<TNumber> FromVector(Vector2 vector)
{
return new NumberOrVector2<TNumber>(default, vector);
}
}
RenderTargetBitmap doesn't take advantage of hardware rendering
Это вообще правильно?
Поток вызывает 1 функцию библиотечную неуправляемого кода, как ее прервать?
V+=1=0+1=1
X+=V=0+1=1
V+=1=1+1=2
X+=V=1+2=3
А теперь, ускорим время в 10 раз, пусть шаг физического движка будет 10сек=1сек, То что будет
V=V0×dt
//...declarations and initializations omitted
do
{
//...some code omitted
if (j != i)
{
swap(i, j);
i = j;
}
} while (j != i);
//...declarations and initializations omitted
do
{
//...some code omitted
if (j != i)
{
swap(i, j);
i = j;
}
else break;
} while (true);
A^k
было бы > 0.99. A
тут - это матрица переходов.O(N^3*ответ)
. Или можно делать хитро: бинарным поиском перебирайте степень, а внутри логарифмическим возведением в степень считайте A^k
. Это будет O(N^3*log(ответ)^2)
. как реализованы в kvm qemu virtualbox бош и другие
Какой там алгоритм замещения(Или его там нету).
void* translate(int acid, int addr){
Запуститься ли обычная ос на виртуальном процессоре(не понимаю как это протестировать. так как образы ос для виртуалок, чет немного другие, а что в них другого в этом вопрос)
Точно не все, к примеру в qemu память выделяется динамически. А значит. Ram может расти. А в реальности, я не могу взять и RAM увеличить в 2 раза по команде. Значит есть инструкция, new которая берет и из неоткуда(с точки зрения вирт ос) берет память.
на виртуальном процессоре
так как образы ос для виртуалок, чет немного другие, а что в них другого в этом вопрос
А значит. Ram может расти.
// в откладке показывает TRUE, но как-будто false отрбатывает
Failed to read static field: Статическая переменная недоступна, поскольку еще не инициализирована. (Исключение из HRESULT: 0x8013131A). The error code is CORDBG_E_STATIC_VAR_NOT_AVAILABLE, or 0x8013131A.
unsafe {
void* x = null; // Можно выводить и Env.Ptr - будет тот же результат
Console.WriteLine((nint)x); // 0
}
В risc вроде там куча csr регистров
на разных компиляторах одна си операция ассемблируется то в комбинацию lui + addi, то в комбинацию auipc +addi
lui
и auipc
. Такие инструкции есть у RISC-V.lui
загружает константу собранную из 20 битов непосредственного значения из инструкции и 12 нулевых младших битов в целевой регистр, а auipc
прибавляет такую же точно константу к PC и загружает в целевой регистр результат сложения, и в этом вся разница между ними.где какая используется не совсем понимаю.
lui
используется для генерации констант, которые не зависят от того, где расположен код, а auipc
для генерации констант, которые двигаются вместе с кодом. Т.е. Если ты хочешь вызвать функцию, которая находится дальше чем ±2К от точки вызова, ты можешь сгенерировать её адрес инструкцией auipc
, и полученный код будет работать одинаково, независимо от того, по какому адресу он будет размещён. А если тебе надо поместить в регистр константу, например 0x12345678, то ты можешь это сделать парой инструкций lui rd, 0x12345 ; addi rd, rd, 0x678
и значение константы будет всегда одинаковым, вне зависимости от того, где будет этот код.Каким образом одинаковые адреса различаются. Или они просто не могут быть одинаковыми(типа ос позаботиться)?
Как они в tlb обрабатываются, если вдруг они реально могут быть одинаковыми, и там нету ни каких дополнительных индексов процесса)
TTBR
с примерно той же функцией, что и cr3
в x86.satp
, содержащий ASID и базовый адрес корневого каталога страничных таблиц. Об этом можно прочитать в разделе 4.1.12 Supervisor Address Translation and Protection (satp) Register спецификации The RISC-V Instruction Set Manual Volume II: Privi....