MODE_TEST,
MODE_PERF,
MODE_GRAD,
+ MODE_SUPPORT,
};
// Output format support similar to llama-bench
-enum output_formats { CONSOLE, SQL };
+enum output_formats { CONSOLE, SQL, CSV };
static const char * output_format_str(output_formats format) {
switch (format) {
return "console";
case SQL:
return "sql";
+ case CSV:
+ return "csv";
default:
GGML_ABORT("invalid output format");
}
format = CONSOLE;
} else if (s == "sql") {
format = SQL;
+ } else if (s == "csv") {
+ format = CSV;
} else {
return false;
}
double bandwidth_gb_s;
size_t memory_kb;
int n_runs;
+ std::string device_description;
+ std::string backend_reg_name;
test_result() {
// Initialize with default values
test_result(const std::string & backend_name, const std::string & op_name, const std::string & op_params,
const std::string & test_mode, bool supported, bool passed, const std::string & error_message = "",
double time_us = 0.0, double flops = 0.0, double bandwidth_gb_s = 0.0, size_t memory_kb = 0,
- int n_runs = 0) :
+ int n_runs = 0, const std::string & device_description = "", const std::string & backend_reg_name = "") :
backend_name(backend_name),
op_name(op_name),
op_params(op_params),
flops(flops),
bandwidth_gb_s(bandwidth_gb_s),
memory_kb(memory_kb),
- n_runs(n_runs) {
+ n_runs(n_runs),
+ device_description(device_description),
+ backend_reg_name(backend_reg_name) {
// Set test time
time_t t = time(NULL);
char buf[32];
static const std::vector<std::string> & get_fields() {
static const std::vector<std::string> fields = {
"test_time", "build_commit", "backend_name", "op_name", "op_params", "test_mode", "supported",
- "passed", "error_message", "time_us", "flops", "bandwidth_gb_s", "memory_kb", "n_runs"
+ "passed", "error_message", "time_us", "flops", "bandwidth_gb_s", "memory_kb", "n_runs",
+ "device_description", "backend_reg_name"
};
return fields;
}
std::to_string(flops),
std::to_string(bandwidth_gb_s),
std::to_string(memory_kb),
- std::to_string(n_runs) };
+ std::to_string(n_runs),
+ device_description,
+ backend_reg_name };
}
};
print_test_console(result);
} else if (result.test_mode == "perf") {
print_perf_console(result);
+ } else if (result.test_mode == "support") {
+ print_support_console(result);
}
}
}
printf("\n");
}
+
+ void print_support_console(const test_result & result) {
+ printf(" %s(%s): ", result.op_name.c_str(), result.op_params.c_str());
+ fflush(stdout);
+
+ if (result.supported) {
+ printf("\033[1;32mSUPPORTED\033[0m\n");
+ } else {
+ printf("\033[1;31mNOT SUPPORTED\033[0m\n");
+ }
+ }
};
struct sql_printer : public printer {
}
};
+struct csv_printer : public printer {
+ void print_header() override {
+ std::vector<std::string> fields = test_result::get_fields();
+ for (size_t i = 0; i < fields.size(); i++) {
+ printf("\"%s\"%s", fields[i].c_str(), i < fields.size() - 1 ? "," : "");
+ }
+ printf("\n");
+ }
+
+ void print_test_result(const test_result & result) override {
+ std::vector<std::string> values = result.get_values();
+ for (size_t i = 0; i < values.size(); i++) {
+ // Escape quotes and wrap in quotes for CSV
+ std::string escaped_value = values[i];
+ size_t pos = 0;
+ while ((pos = escaped_value.find("\"", pos)) != std::string::npos) {
+ escaped_value.replace(pos, 1, "\"\"");
+ pos += 2;
+ }
+ printf("\"%s\"%s", escaped_value.c_str(), i < values.size() - 1 ? "," : "");
+ }
+ printf("\n");
+ }
+};
+
static std::unique_ptr<printer> create_printer(output_formats format) {
switch (format) {
case CONSOLE:
return std::make_unique<console_printer>();
case SQL:
return std::make_unique<sql_printer>();
+ case CSV:
+ return std::make_unique<csv_printer>();
}
GGML_ABORT("invalid output format");
}
std::vector<ggml_tensor *> sentinels;
void add_sentinel(ggml_context * ctx) {
- if (mode == MODE_PERF || mode == MODE_GRAD) {
+ if (mode == MODE_PERF || mode == MODE_GRAD || mode == MODE_SUPPORT) {
return;
}
ggml_tensor * sentinel = ::ggml_new_tensor_1d(ctx, GGML_TYPE_F32, sentinel_size);
return true;
}
- // check if backends support op
if (!ggml_backend_supports_op(backend, out)) {
// Create test result for unsupported performance test
test_result result(ggml_backend_name(backend), current_op_name, vars(), "perf", false, false,
"not supported");
- if (output_printer) {
- output_printer->print_test_result(result);
- }
+ output_printer->print_test_result(result);
return true;
}
return true;
}
+ bool eval_support(ggml_backend_t backend, const char * op_name, printer * output_printer) {
+ mode = MODE_SUPPORT;
+
+ static const size_t graph_nodes = 8192;
+
+ ggml_init_params params = {
+ /* .mem_size = */ ggml_tensor_overhead()*128 + ggml_graph_overhead_custom(graph_nodes, false),
+ /* .mem_base = */ NULL,
+ /* .no_alloc = */ true,
+ };
+ ggml_context_ptr ctx(ggml_init(params)); // smart ptr
+ GGML_ASSERT(ctx);
+
+ ggml_tensor * out = build_graph(ctx.get());
+ std::string current_op_name = op_desc(out);
+ if (op_name != nullptr && current_op_name != op_name) {
+ return true;
+ }
+
+ bool supported = ggml_backend_supports_op(backend, out);
+
+ std::string device_desc = ggml_backend_dev_description(ggml_backend_get_device(backend));
+ std::string backend_reg_name = ggml_backend_reg_name(ggml_backend_dev_backend_reg(ggml_backend_get_device(backend)));
+
+ test_result result(ggml_backend_name(backend), current_op_name, vars(), "support", supported, supported,
+ supported ? "yes" : "no", 0.0, 0.0, 0.0, 0, 0, device_desc, backend_reg_name);
+
+ output_printer->print_test_result(result);
+
+ return true;
+ }
+
bool eval_grad(ggml_backend_t backend, const char * op_name, printer * output_printer) {
mode = MODE_GRAD;
const std::vector<float> expect = grad_expect();
return true;
}
+ if (mode == MODE_SUPPORT) {
+ auto test_cases = make_test_cases_eval();
+ filter_test_cases(test_cases, params_filter);
+ for (auto & test : test_cases) {
+ test->eval_support(backend, op_name, output_printer);
+ }
+ return true;
+ }
+
GGML_ABORT("fatal error");
}
static void usage(char ** argv) {
- printf("Usage: %s [mode] [-o <op>] [-b <backend>] [-p <params regex>] [--output <console|sql>]\n", argv[0]);
+ printf("Usage: %s [mode] [-o <op>] [-b <backend>] [-p <params regex>] [--output <console|sql|csv>]\n", argv[0]);
printf(" valid modes:\n");
printf(" - test (default, compare with CPU backend for correctness)\n");
printf(" - grad (compare gradients from backpropagation with method of finite differences)\n");
printf(" - perf (performance evaluation)\n");
+ printf(" - support (probe backend operation support)\n");
printf(" op names for -o are as given by ggml_op_desc() (e.g. ADD, MUL_MAT, etc)\n");
- printf(" --output specifies output format (default: console)\n");
+ printf(" --output specifies output format (default: console, options: console, sql, csv)\n");
}
int main(int argc, char ** argv) {
mode = MODE_PERF;
} else if (strcmp(argv[i], "grad") == 0) {
mode = MODE_GRAD;
+ } else if (strcmp(argv[i], "support") == 0) {
+ mode = MODE_SUPPORT;
} else if (strcmp(argv[i], "-o") == 0) {
if (i + 1 < argc) {
op_name_filter = argv[++i];