Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assign frequently used constant value in code on stack #138

Merged
merged 2 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/interpreter/ByteCode.h
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,6 @@ class Const128 : public ByteCode {
{
printf("const128 ");
DUMP_BYTECODE_OFFSET(dstOffset);
//printf("value: %" PRIu64, m_value);
}
#endif

Expand Down
265 changes: 203 additions & 62 deletions src/parser/WASMParser.cpp

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion src/runtime/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,13 @@ void DefinedFunction::call(ExecutionState& state, const uint32_t argc, Value* ar
}

// init local space
auto localSize = m_moduleFunction->requiredStackSizeDueToLocal();
auto localSize = m_moduleFunction->requiredStackSizeDueToParameterAndLocal()
- m_moduleFunction->functionType()->paramStackSize();
memset(functionStackPointer, 0, localSize);
functionStackPointer += localSize;

// init constant space
memcpy(functionStackPointer, m_moduleFunction->constantData(), m_moduleFunction->constantDataSize());

auto resultOffsets = Interpreter::interpret(newState, functionStackBase);

Expand Down
63 changes: 58 additions & 5 deletions src/runtime/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ namespace Walrus {
ModuleFunction::ModuleFunction(FunctionType* functionType)
: m_functionType(functionType)
, m_requiredStackSize(std::max(m_functionType->paramStackSize(), m_functionType->resultStackSize()))
, m_requiredStackSizeDueToLocal(0)
, m_requiredStackSizeDueToParameterAndLocal(0)
{
}

Expand Down Expand Up @@ -363,7 +363,7 @@ Instance* Module::instantiate(ExecutionState& state, const ExternVector& imports

#if !defined(NDEBUG)

static const char* localTypeName(Value::Type v)
static const char* typeName(Value::Type v)
{
switch (v) {
case Value::I32:
Expand All @@ -385,18 +385,71 @@ static const char* localTypeName(Value::Type v)
}
}

static void dumpValue(Value v)
{
switch (v.type()) {
case Value::I32:
printf("%" PRId32, v.asI32());
break;
case Value::I64:
printf("%" PRId64, v.asI64());
break;
case Value::F32:
printf("%f", v.asF32());
break;
case Value::F64:
printf("%lf", v.asF64());
break;
case Value::V128:
printf("%" PRIu8, v.asV128().m_data[0]);
printf(" %" PRIu8, v.asV128().m_data[1]);
printf(" %" PRIu8, v.asV128().m_data[2]);
printf(" %" PRIu8, v.asV128().m_data[3]);
printf(" %" PRIu8, v.asV128().m_data[4]);
printf(" %" PRIu8, v.asV128().m_data[5]);
printf(" %" PRIu8, v.asV128().m_data[6]);
printf(" %" PRIu8, v.asV128().m_data[7]);
printf(" %" PRIu8, v.asV128().m_data[8]);
printf(" %" PRIu8, v.asV128().m_data[9]);
printf(" %" PRIu8, v.asV128().m_data[10]);
printf(" %" PRIu8, v.asV128().m_data[11]);
printf(" %" PRIu8, v.asV128().m_data[12]);
printf(" %" PRIu8, v.asV128().m_data[13]);
printf(" %" PRIu8, v.asV128().m_data[14]);
printf(" %" PRIu8, v.asV128().m_data[15]);
break;
case Value::FuncRef:
break;
case Value::ExternRef:
break;
default:
RELEASE_ASSERT_NOT_REACHED();
}
printf(", %s", typeName(v.type()));
}

void ModuleFunction::dumpByteCode()
{
printf("\n");
printf("required stack size: %u bytes\n", m_requiredStackSize);
printf("required stack size due to local: %u bytes\n", m_requiredStackSizeDueToLocal);
printf("required stack size due to parameter and local: %u bytes\n", m_requiredStackSizeDueToParameterAndLocal);
printf("stack: [");
size_t pos = 0;
for (size_t i = 0; i < m_functionType->param().size(); i++) {
printf("%zu(parameter %zu, %s) ", pos, i, typeName(m_functionType->param()[i]));
pos += valueStackAllocatedSize(m_functionType->param()[i]);
}
for (size_t i = 0; i < m_local.size(); i++) {
printf("%zu(local %zu, %s) ", pos, i, localTypeName(m_local[i]));
printf("%zu(local %zu, %s) ", pos, i, typeName(m_local[i]));
pos += valueStackAllocatedSize(m_local[i]);
}
printf("%zu(%" PRIu32 " bytes for general operation)]\n", pos, (m_requiredStackSize - m_requiredStackSizeDueToLocal));
for (size_t i = 0; i < m_constantDebugData.size(); i++) {
printf("%zu(constant ", pos);
dumpValue(m_constantDebugData[i]);
printf(") ");
pos += valueStackAllocatedSize(m_constantDebugData[i].type());
}
printf("%zu(%" PRIu32 " bytes for general operation)]\n", pos, (m_requiredStackSize - m_requiredStackSizeDueToParameterAndLocal));
printf("bytecode size: %zu bytes\n", m_byteCode.size());
printf("\n");

Expand Down
13 changes: 10 additions & 3 deletions src/runtime/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ class ModuleFunction {

FunctionType* functionType() const { return m_functionType; }
uint32_t requiredStackSize() const { return m_requiredStackSize; }
uint32_t requiredStackSizeDueToLocal() const { return m_requiredStackSizeDueToLocal; }
uint32_t requiredStackSizeDueToParameterAndLocal() const { return m_requiredStackSizeDueToParameterAndLocal; }

template <typename CodeType>
void pushByteCode(const CodeType& code)
Expand Down Expand Up @@ -208,7 +208,9 @@ class ModuleFunction {
return m_byteCode.size();
}

uint8_t* byteCode() { return m_byteCode.data(); }
const uint8_t* byteCode() const { return m_byteCode.data(); }
const uint8_t* constantData() const { return m_constantData.data(); }
size_t constantDataSize() const { return m_constantData.size(); }
#if !defined(NDEBUG)
void dumpByteCode();
#endif
Expand All @@ -220,10 +222,15 @@ class ModuleFunction {

private:
FunctionType* m_functionType;
// m_requiredStackSize = m_requiredStackSizeDueToParameterAndLocal + constant space + general purpose space
uint32_t m_requiredStackSize;
uint32_t m_requiredStackSizeDueToLocal;
uint32_t m_requiredStackSizeDueToParameterAndLocal;
ValueTypeVector m_local;
Vector<uint8_t, std::allocator<uint8_t>> m_byteCode;
Vector<uint8_t, std::allocator<uint8_t>> m_constantData;
#if !defined(NDEBUG)
Vector<Value, std::allocator<Value>> m_constantDebugData;
#endif
Vector<CatchInfo, std::allocator<CatchInfo>> m_catchInfo;
};

Expand Down
7 changes: 7 additions & 0 deletions src/runtime/Value.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ struct Vec128 {
{
}

bool operator==(const Vec128& src) const
{
return memcmp(m_data, src.m_data, 16) == 0;
}

float asF32(int lane) const { return to<float>(lane); }
uint32_t asF32Bits(int lane) const { return to<uint32_t>(lane); }
double asF64(int lane) const { return to<double>(lane); }
Expand Down Expand Up @@ -348,6 +353,8 @@ class Value {
case FuncRef:
case ExternRef:
return m_ref == v.m_ref;
case V128:
return m_v128 == v.m_v128;
default:
ASSERT_NOT_REACHED();
break;
Expand Down
52 changes: 20 additions & 32 deletions test/wasmBenchmarker/benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ def prepare_arg_pars():
const='./ctests', default='./ctests')
parser.add_argument('--only-game', help='only run The Benchmarks Game tests', action='store_true')
parser.add_argument('--run', metavar='TEST', help='only run one benchmark')
parser.add_argument('--walrus', metavar='PATH', help='path to the engine', nargs='?', const='./engines/walrus',
type=str)
parser.add_argument('--walrus', metavar='PATH', help='path to the engine', nargs='+', default=['walrus'])
parser.add_argument('--report', metavar='PATH', help='path to the report', nargs='?', const='./report.md')
parser.add_argument('--iterations', metavar='NUMBER', help='how many times run the tests', nargs='?',
const='10', default=10, type=int)
Expand All @@ -64,9 +63,11 @@ def check_programs(walrus):
print("git not found")
exit(1)

if walrus is not None and os.path.isfile(walrus) is False:
print("walrus not found")
exit(1)
for w in walrus:
path = w.split(" ")[0]
if os.path.isfile(path) is False:
print(path + " not found")
exit(1)

print("Checks done")

Expand Down Expand Up @@ -116,24 +117,6 @@ def compile_tests(path, only_game=False, compile_anyway=False, run=None):

return test_names


def run_walrus_jit(engine, path, name):
if not os.path.exists(path):
print("invalid path for walrus run")
exit(1)

result = subprocess.check_output(engine + " --run-export runtime --jit " + path + "/wasm/" + name + ".wasm",
shell=True)

if float(f'{float(result):.9f}') != float(expectedValues[name]):
print("walrus jit failed with " + name + ".wasm", file=sys.stderr)
print("Expected: " + str(expectedValues[name]), file=sys.stderr)
print("Got: " + str(result), file=sys.stderr)
return False

return True


def run_walrus(engine, path, name):
if not os.path.exists(path):
print("invalid path for walrus run")
Expand Down Expand Up @@ -170,21 +153,26 @@ def run_tests(path, test_names, walrus, number_of_runs):
ret_val = []
for name in test_names:
print("running " + name)
measurements_walrus = []
measurements_walrus_jit = []
measurements_walrus = {}
for w in walrus:
measurements_walrus[w] = []

for i in range(0, number_of_runs):
print("round " + str(i + 1))
measurements_walrus.append(measure_time(path, name, run_walrus, walrus))
measurements_walrus_jit.append(measure_time(path, name, run_walrus_jit, walrus))
for w in walrus:
measurements_walrus[w].append(measure_time(path, name, run_walrus, w))

result_list = {"test": name}

min_walrus = min(measurements_walrus)
min_walrus_jit = min(measurements_walrus_jit)
result_list["walrus [s]"] = "{:.3f}".format(min_walrus / 1000000000) + " ({:.3f}x)".format(1)
result_list["walrus-jit [s]"] = "{:.3f}".format(min_walrus_jit / 1000000000) + " ({:.3f}x)".format(
(min_walrus / min_walrus_jit))
min_walrus_first = False
min_walrus = {}
for w in walrus:
min_walrus[w] = min(measurements_walrus[w])
if min_walrus_first is False:
min_walrus_first = min_walrus[w]

for w in walrus:
result_list[w + " [s]"] = "{:.3f}".format(min_walrus[w] / 1000000000) + " ({:.3f}x)".format((min_walrus[w] / min_walrus_first))

ret_val.append(result_list)

Expand Down