<commit_before>// Generates Documentation

gb_global int print_entity_kind_ordering[Entity_Count] = {
	/*Invalid*/     -1,
	/*Constant*/    0,
	/*Variable*/    1,
	/*TypeName*/    4,
	/*Procedure*/   2,
	/*ProcGroup*/   3,
	/*Builtin*/     -1,
	/*ImportName*/  -1,
	/*LibraryName*/ -1,
	/*Nil*/         -1,
	/*Label*/       -1,
};
gb_global char const *print_entity_names[Entity_Count] = {
	/*Invalid*/     "",
	/*Constant*/    "constants",
	/*Variable*/    "variables",
	/*TypeName*/    "types",
	/*Procedure*/   "procedures",
	/*ProcGroup*/   "proc_group",
	/*Builtin*/     "",
	/*ImportName*/  "import names",
	/*LibraryName*/ "library names",
	/*Nil*/         "",
	/*Label*/       "",
};

GB_COMPARE_PROC(cmp_entities_for_printing) {
	GB_ASSERT(a != nullptr);
	GB_ASSERT(b != nullptr);
	Entity *x = *cast(Entity **)a;
	Entity *y = *cast(Entity **)b;
	int res = 0;
	res = string_compare(x->pkg->name, y->pkg->name);
	if (res != 0) {
		return res;
	}
	int ox = print_entity_kind_ordering[x->kind];
	int oy = print_entity_kind_ordering[y->kind];
	if (ox < oy) {
		return -1;
	} else if (ox > oy) {
		return +1;
	}
	res = string_compare(x->token.string, y->token.string);
	return res;
}

GB_COMPARE_PROC(cmp_ast_package_by_name) {
	GB_ASSERT(a != nullptr);
	GB_ASSERT(b != nullptr);
	AstPackage *x = *cast(AstPackage **)a;
	AstPackage *y = *cast(AstPackage **)b;
	return string_compare(x->name, y->name);
}

String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
	isize len = 0;
	for_array(i, g.list) {
		String comment = g.list[i].string;
		len += comment.len;
		len += 1; // for \n
	}
	if (len == 0) {
		return make_string(nullptr, 0);
	}

	u8 *text = gb_alloc_array(a, u8, len+1);
	len = 0;
	for_array(i, g.list) {
		String comment = g.list[i].string;
		if (comment[1] == '/') {
			comment.text += 2;
			comment.len  -= 2;
		} else if (comment[1] == '*') {
			comment.text += 2;
			comment.len  -= 4;
		}
		comment = string_trim_whitespace(comment);
		gb_memmove(text+len, comment.text, comment.len);
		len += comment.len;
		text[len++] = '\n';
	}
	return make_string(text, len);
}

void print_doc_line(i32 indent, char const *fmt, ...) {
	while (indent --> 0) {
		gb_printf("\t");
	}
	va_list va;
	va_start(va, fmt);
	gb_printf_va(fmt, va);
	va_end(va);
	gb_printf("\n");
}
void print_doc_line_no_newline(i32 indent, char const *fmt, ...) {
	while (indent --> 0) {
		gb_printf("\t");
	}
	va_list va;
	va_start(va, fmt);
	gb_printf_va(fmt, va);
	va_end(va);
}

bool print_doc_comment_group_string(i32 indent, CommentGroup *g) {
	if (g == nullptr) {
		return false;
	}
	isize len = 0;
	for_array(i, g->list) {
		String comment = g->list[i].string;
		len += comment.len;
		len += 1; // for \n
	}
	if (len <= g->list.count) {
		return false;
	}

	isize count = 0;
	for_array(i, g->list) {
		String comment = g->list[i].string;
		if (comment[1] == '/') {
			comment.text += 2;
			comment.len  -= 2;
		} else if (comment[1] == '*') {
			comment.text += 2;
			comment.len  -= 4;
		}
		if (comment.len > 0 && comment[0] == ' ') {
			comment.text += 1;
			comment.len  -= 1;
		}

		if (string_starts_with(comment, str_lit("@("))) {
			continue;
		}

		print_doc_line(indent, "%.*s", LIT(comment));
		count += 1;
	}
	return count > 0;
}

void print_doc_expr(Ast *expr) {
	gbString s = nullptr;
	if (build_context.cmd_doc_flags & CmdDocFlag_All) {
		s = expr_to_string(expr);
	} else {
		s = expr_to_string_shorthand(expr);
	}
	gb_file_write(gb_file_get_standard(gbFileStandard_Output), s, gb_string_length(s));
	gb_string_free(s);
}

void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
	if (pkg == nullptr) {
		return;
	}

	print_doc_line(0, "package %.*s", LIT(pkg->name));

	for_array(i, pkg->files) {
		AstFile *f = pkg->files[i];
		if (f->pkg_decl) {
			GB_ASSERT(f->pkg_decl->kind == Ast_PackageDecl);
			print_doc_comment_group_string(1, f->pkg_decl->PackageDecl.docs);
		}
	}

	if (pkg->scope != nullptr) {
		auto entities = array_make<Entity *>(heap_allocator(), 0, pkg->scope->elements.entries.count);
		defer (array_free(&entities));
		for_array(i, pkg->scope->elements.entries) {
			Entity *e = pkg->scope->elements.entries[i].value;
			switch (e->kind) {
			case Entity_Invalid:
			case Entity_Builtin:
			case Entity_Nil:
			case Entity_Label:
				continue;
			case Entity_Constant:
			case Entity_Variable:
			case Entity_TypeName:
			case Entity_Procedure:
			case Entity_ProcGroup:
			case Entity_ImportName:
			case Entity_LibraryName:
				// Fine
				break;
			}
			array_add(&entities, e);
		}
		gb_sort_array(entities.data, entities.count, cmp_entities_for_printing);

		AstPackage *curr_pkg = nullptr;
		EntityKind curr_entity_kind = Entity_Invalid;
		for_array(i, entities) {
			Entity *e = entities[i];
			if (e->pkg != pkg) {
				continue;
			}
			if (!is_entity_exported(e)) {
				continue;
			}

			if (curr_entity_kind != e->kind) {
				curr_entity_kind = e->kind;
				print_doc_line(0, "");
				print_doc_line(1, "%s", print_entity_names[e->kind]);
			}

			Ast *type_expr = nullptr;
			Ast *init_expr = nullptr;
			Ast *decl_node = nullptr;
			CommentGroup *comment = nullptr;
			CommentGroup *docs = nullptr;
			if (e->decl_info != nullptr) {
				type_expr = e->decl_info->type_expr;
				init_expr = e->decl_info->init_expr;
				decl_node = e->decl_info->decl_node;
				comment = e->decl_info->comment;
				docs = e->decl_info->docs;
			}
			GB_ASSERT(type_expr != nullptr || init_expr != nullptr);
			print_doc_line_no_newline(2, "%.*s", LIT(e->token.string));
			if (type_expr != nullptr) {
				gbString t = expr_to_string(type_expr);
				gb_printf(": %s ", t);
				gb_string_free(t);
			} else {
				gb_printf(" :");
			}
			if (e->kind == Entity_Variable) {
				if (init_expr != nullptr) {
					gb_printf("= ");
					print_doc_expr(init_expr);
				}
			} else {
				gb_printf(": ");
				print_doc_expr(init_expr);
			}

			gb_printf(";\n");

			if (build_context.cmd_doc_flags & CmdDocFlag_All) {
				if (comment) {
					// gb_printf(" <comment>");
				}
				if (print_doc_comment_group_string(3, docs)) {
					gb_printf("\n");
				}
			}
		}
		print_doc_line(0, "");
	}

	if (pkg->fullpath.len != 0) {
		print_doc_line(0, "");
		print_doc_line(1, "fullpath: %.*s", LIT(pkg->fullpath));
		print_doc_line(1, "files:");
		for_array(i, pkg->files) {
			AstFile *f = pkg->files[i];
			String filename = remove_directory_from_path(f->fullpath);
			print_doc_line(2, "%.*s", LIT(filename));
		}
	}

}

void generate_documentation(Checker *c) {
	CheckerInfo *info = &c->info;

	if (build_context.doc_packages.count != 0) {
		auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
		bool was_error = false;
		for_array(j, build_context.doc_packages) {
			bool found = false;
			String name = build_context.doc_packages[j];
			for_array(i, info->packages.entries) {
				AstPackage *pkg = info->packages.entries[i].value;
				if (name == pkg->name) {
					found = true;
					array_add(&pkgs, pkg);
					break;
				}
			}
			if (!found) {
				gb_printf_err("Unknown package %.*s\n", LIT(name));
				was_error = true;
			}
		}
		if (was_error) {
			gb_exit(1);
			return;
		}

		gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);

		for_array(i, pkgs) {
			print_doc_package(info, pkgs[i]);
		}
	} else if (build_context.cmd_doc_flags & CmdDocFlag_AllPackages) {
		auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
		for_array(i, info->packages.entries) {
			AstPackage *pkg = info->packages.entries[i].value;
			array_add(&pkgs, pkg);
		}

		gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);

		for_array(i, pkgs) {
			print_doc_package(info, pkgs[i]);
		}
	} else {
		GB_ASSERT(info->init_scope->flags & ScopeFlag_Pkg);
		AstPackage *pkg = info->init_scope->pkg;
		print_doc_package(info, pkg);

	}
}
<commit_msg>Improve file doc logic<commit_after>// Generates Documentation

gb_global int print_entity_kind_ordering[Entity_Count] = {
	/*Invalid*/     -1,
	/*Constant*/    0,
	/*Variable*/    1,
	/*TypeName*/    4,
	/*Procedure*/   2,
	/*ProcGroup*/   3,
	/*Builtin*/     -1,
	/*ImportName*/  -1,
	/*LibraryName*/ -1,
	/*Nil*/         -1,
	/*Label*/       -1,
};
gb_global char const *print_entity_names[Entity_Count] = {
	/*Invalid*/     "",
	/*Constant*/    "constants",
	/*Variable*/    "variables",
	/*TypeName*/    "types",
	/*Procedure*/   "procedures",
	/*ProcGroup*/   "proc_group",
	/*Builtin*/     "",
	/*ImportName*/  "import names",
	/*LibraryName*/ "library names",
	/*Nil*/         "",
	/*Label*/       "",
};

GB_COMPARE_PROC(cmp_entities_for_printing) {
	GB_ASSERT(a != nullptr);
	GB_ASSERT(b != nullptr);
	Entity *x = *cast(Entity **)a;
	Entity *y = *cast(Entity **)b;
	int res = 0;
	res = string_compare(x->pkg->name, y->pkg->name);
	if (res != 0) {
		return res;
	}
	int ox = print_entity_kind_ordering[x->kind];
	int oy = print_entity_kind_ordering[y->kind];
	if (ox < oy) {
		return -1;
	} else if (ox > oy) {
		return +1;
	}
	res = string_compare(x->token.string, y->token.string);
	return res;
}

GB_COMPARE_PROC(cmp_ast_package_by_name) {
	GB_ASSERT(a != nullptr);
	GB_ASSERT(b != nullptr);
	AstPackage *x = *cast(AstPackage **)a;
	AstPackage *y = *cast(AstPackage **)b;
	return string_compare(x->name, y->name);
}

String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
	isize len = 0;
	for_array(i, g.list) {
		String comment = g.list[i].string;
		len += comment.len;
		len += 1; // for \n
	}
	if (len == 0) {
		return make_string(nullptr, 0);
	}

	u8 *text = gb_alloc_array(a, u8, len+1);
	len = 0;
	for_array(i, g.list) {
		String comment = g.list[i].string;
		if (comment[1] == '/') {
			comment.text += 2;
			comment.len  -= 2;
		} else if (comment[1] == '*') {
			comment.text += 2;
			comment.len  -= 4;
		}
		comment = string_trim_whitespace(comment);
		gb_memmove(text+len, comment.text, comment.len);
		len += comment.len;
		text[len++] = '\n';
	}
	return make_string(text, len);
}

void print_doc_line(i32 indent, char const *fmt, ...) {
	while (indent --> 0) {
		gb_printf("\t");
	}
	va_list va;
	va_start(va, fmt);
	gb_printf_va(fmt, va);
	va_end(va);
	gb_printf("\n");
}
void print_doc_line_no_newline(i32 indent, char const *fmt, ...) {
	while (indent --> 0) {
		gb_printf("\t");
	}
	va_list va;
	va_start(va, fmt);
	gb_printf_va(fmt, va);
	va_end(va);
}

bool print_doc_comment_group_string(i32 indent, CommentGroup *g) {
	if (g == nullptr) {
		return false;
	}
	isize len = 0;
	for_array(i, g->list) {
		String comment = g->list[i].string;
		len += comment.len;
		len += 1; // for \n
	}
	if (len <= g->list.count) {
		return false;
	}

	isize count = 0;
	for_array(i, g->list) {
		String comment = g->list[i].string;
		if (comment[1] == '/') {
			comment.text += 2;
			comment.len  -= 2;
		} else if (comment[1] == '*') {
			comment.text += 2;
			comment.len  -= 4;
		}
		if (comment.len > 0 && comment[0] == ' ') {
			comment.text += 1;
			comment.len  -= 1;
		}

		if (string_starts_with(comment, str_lit("@("))) {
			continue;
		}

		print_doc_line(indent, "%.*s", LIT(comment));
		count += 1;
	}
	return count > 0;
}

void print_doc_expr(Ast *expr) {
	gbString s = nullptr;
	if (build_context.cmd_doc_flags & CmdDocFlag_All) {
		s = expr_to_string(expr);
	} else {
		s = expr_to_string_shorthand(expr);
	}
	gb_file_write(gb_file_get_standard(gbFileStandard_Output), s, gb_string_length(s));
	gb_string_free(s);
}

void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
	if (pkg == nullptr) {
		return;
	}

	print_doc_line(0, "package %.*s", LIT(pkg->name));

	for_array(i, pkg->files) {
		AstFile *f = pkg->files[i];
		if (f->pkg_decl) {
			GB_ASSERT(f->pkg_decl->kind == Ast_PackageDecl);
			if (print_doc_comment_group_string(1, f->pkg_decl->PackageDecl.docs)) {
				print_doc_line(0, "");
			}
		}
	}

	if (pkg->scope != nullptr) {
		auto entities = array_make<Entity *>(heap_allocator(), 0, pkg->scope->elements.entries.count);
		defer (array_free(&entities));
		for_array(i, pkg->scope->elements.entries) {
			Entity *e = pkg->scope->elements.entries[i].value;
			switch (e->kind) {
			case Entity_Invalid:
			case Entity_Builtin:
			case Entity_Nil:
			case Entity_Label:
				continue;
			case Entity_Constant:
			case Entity_Variable:
			case Entity_TypeName:
			case Entity_Procedure:
			case Entity_ProcGroup:
			case Entity_ImportName:
			case Entity_LibraryName:
				// Fine
				break;
			}
			array_add(&entities, e);
		}
		gb_sort_array(entities.data, entities.count, cmp_entities_for_printing);

		EntityKind curr_entity_kind = Entity_Invalid;
		for_array(i, entities) {
			Entity *e = entities[i];
			if (e->pkg != pkg) {
				continue;
			}
			if (!is_entity_exported(e)) {
				continue;
			}

			if (curr_entity_kind != e->kind) {
				if (curr_entity_kind != Entity_Invalid) {
					print_doc_line(0, "");
				}
				curr_entity_kind = e->kind;
				print_doc_line(1, "%s", print_entity_names[e->kind]);
			}

			Ast *type_expr = nullptr;
			Ast *init_expr = nullptr;
			Ast *decl_node = nullptr;
			CommentGroup *comment = nullptr;
			CommentGroup *docs = nullptr;
			if (e->decl_info != nullptr) {
				type_expr = e->decl_info->type_expr;
				init_expr = e->decl_info->init_expr;
				decl_node = e->decl_info->decl_node;
				comment = e->decl_info->comment;
				docs = e->decl_info->docs;
			}
			GB_ASSERT(type_expr != nullptr || init_expr != nullptr);
			print_doc_line_no_newline(2, "%.*s", LIT(e->token.string));
			if (type_expr != nullptr) {
				gbString t = expr_to_string(type_expr);
				gb_printf(": %s ", t);
				gb_string_free(t);
			} else {
				gb_printf(" :");
			}
			if (e->kind == Entity_Variable) {
				if (init_expr != nullptr) {
					gb_printf("= ");
					print_doc_expr(init_expr);
				}
			} else {
				gb_printf(": ");
				print_doc_expr(init_expr);
			}

			gb_printf(";\n");

			if (build_context.cmd_doc_flags & CmdDocFlag_All) {
				if (comment) {
					// gb_printf(" <comment>");
				}
				if (print_doc_comment_group_string(3, docs)) {
					gb_printf("\n");
				}
			}
		}
		print_doc_line(0, "");
	}

	if (pkg->fullpath.len != 0) {
		print_doc_line(0, "");
		print_doc_line(1, "fullpath: %.*s", LIT(pkg->fullpath));
		print_doc_line(1, "files:");
		for_array(i, pkg->files) {
			AstFile *f = pkg->files[i];
			String filename = remove_directory_from_path(f->fullpath);
			print_doc_line(2, "%.*s", LIT(filename));
		}
	}

}

void generate_documentation(Checker *c) {
	CheckerInfo *info = &c->info;

	if (build_context.doc_packages.count != 0) {
		auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
		bool was_error = false;
		for_array(j, build_context.doc_packages) {
			bool found = false;
			String name = build_context.doc_packages[j];
			for_array(i, info->packages.entries) {
				AstPackage *pkg = info->packages.entries[i].value;
				if (name == pkg->name) {
					found = true;
					array_add(&pkgs, pkg);
					break;
				}
			}
			if (!found) {
				gb_printf_err("Unknown package %.*s\n", LIT(name));
				was_error = true;
			}
		}
		if (was_error) {
			gb_exit(1);
			return;
		}

		gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);

		for_array(i, pkgs) {
			print_doc_package(info, pkgs[i]);
		}
	} else if (build_context.cmd_doc_flags & CmdDocFlag_AllPackages) {
		auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
		for_array(i, info->packages.entries) {
			AstPackage *pkg = info->packages.entries[i].value;
			array_add(&pkgs, pkg);
		}

		gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);

		for_array(i, pkgs) {
			print_doc_package(info, pkgs[i]);
		}
	} else {
		GB_ASSERT(info->init_scope->flags & ScopeFlag_Pkg);
		AstPackage *pkg = info->init_scope->pkg;
		print_doc_package(info, pkg);

	}
}
<|endoftext|>


<commit_before>#include "dp.h"

#include <memory>

DynamicParallelism::DynamicParallelism()
{
	runtime  = clRuntime::getInstance();
	file     = clFile::getInstance();

	platform = runtime->getPlatformID();
	device   = runtime->getDevice();
	context  = runtime->getContext();
	cmdQueue = runtime->getCmdQueue(0);

	glbSize = 8192;
	locSize = 256;
	factor  = 2.3f;

	init();
}

DynamicParallelism::~DynamicParallelism()
{
	clean();
}

void DynamicParallelism::init()
{
	initKernel();
	initBuffer();
}

void DynamicParallelism::initKernel()
{
	cl_int err;

	// Open kernel file
        file->open("dp_Kernels.cl");

        // Create program
        const char *source = file->getSourceChar();
        program = clCreateProgramWithSource(context, 1,
                (const char **)&source, NULL, &err);
        checkOpenCLErrors(err, "Failed to create Program with source\n");

        // Create program with OpenCL 2.0 support
        err = clBuildProgram(program, 0, NULL, "-I. -cl-std=CL2.0", NULL, NULL);
        checkOpenCLErrors(err, "Failed to build program...\n");

        // Create kernels
        kernel_saxpy_naive = clCreateKernel(program, "saxpy_naive", &err);
        checkOpenCLErrors(err, "Failed to create saxpy_naive kernel");
        kernel_saxpy_stride = clCreateKernel(program, "saxpy_stride", &err);
        checkOpenCLErrors(err, "Failed to create saxpy_stride kernel");
        kernel_saxpy_dp = clCreateKernel(program, "saxpy_dp", &err);
        checkOpenCLErrors(err, "Failed to create saxpy_dp kernel");
}

void DynamicParallelism::initBuffer()
{
	cl_int err;
	size_t glbSizeBytes = glbSize * sizeof(float);

	saxpy_src_0 = (float *)clSVMAlloc(context, CL_MEM_READ_ONLY, glbSizeBytes, 0);
	saxpy_src_1 = (float *)clSVMAlloc(context, CL_MEM_READ_ONLY, glbSizeBytes, 0);
	saxpy_dst_0 = (float *)clSVMAlloc(context, CL_MEM_READ_WRITE, glbSizeBytes, 0);

	float two = 2.0f;
	float three = 3.0f;

	err  = clEnqueueSVMMemFill(cmdQueue, saxpy_src_0, (const void *)&two, sizeof(float), glbSizeBytes, 0, NULL, NULL);
	err |= clEnqueueSVMMemFill(cmdQueue, saxpy_src_1, (const void *)&three, sizeof(float), glbSizeBytes, 0, NULL, NULL);
	checkOpenCLErrors(err, "Failed to fill SVM buffers");

	err = clFlush(cmdQueue);
	checkOpenCLErrors(err, "Failed to clFlush cmdQueue");

	// Map SVM buffers
	err  = clEnqueueSVMMap(cmdQueue, CL_TRUE, CL_MEM_READ_WRITE, saxpy_src_0, glbSizeBytes, 0, NULL, NULL);
	err |= clEnqueueSVMMap(cmdQueue, CL_TRUE, CL_MEM_READ_WRITE, saxpy_src_1, glbSizeBytes, 0, NULL, NULL);
	checkOpenCLErrors(err, "Failed to map SVM buffers for initialization");

	// Initialize buffers
	for (int i = 0; i < glbSize; ++i)
		printf("%f %f\n", saxpy_src_0[i], saxpy_src_1[i]);

	// Unmap SVM buffers
	err  = clEnqueueSVMUnmap(cmdQueue, saxpy_src_0, 0, NULL, NULL);
	err |= clEnqueueSVMUnmap(cmdQueue, saxpy_src_1, 0, NULL, NULL);
	checkOpenCLErrors(err, "Failed to unmap SVM buffers after initialization");

}

void DynamicParallelism::clean()
{
	cleanKernel();
	cleanBuffer();
}

void DynamicParallelism::cleanKernel()
{
	cl_int err;

	err = clReleaseKernel(kernel_saxpy_naive);
	err |= clReleaseKernel(kernel_saxpy_stride);
	err |= clReleaseKernel(kernel_saxpy_dp);
	checkOpenCLErrors(err, "Failed to release kernels");

	err = clReleaseProgram(program);
	checkOpenCLErrors(err, "Failed to release program");
}

void DynamicParallelism::cleanBuffer()
{
	clSVMFreeSafe(context, saxpy_src_0);
	clSVMFreeSafe(context, saxpy_src_1);
	clSVMFreeSafe(context, saxpy_dst_0);
}

void DynamicParallelism::runNaive()
{
	cl_int err;

	size_t globalSize = glbSize;
	size_t localSize  = locSize;

	err  = clSetKernelArg(kernel_saxpy_naive, 0, sizeof(int), (void *)&glbSize);
	err |= clSetKernelArg(kernel_saxpy_naive, 1, sizeof(int), (void *)&factor);
	err |= clSetKernelArgSVMPointer(kernel_saxpy_naive, 2, saxpy_src_0);
	err |= clSetKernelArgSVMPointer(kernel_saxpy_naive, 3, saxpy_src_1);
	err |= clSetKernelArgSVMPointer(kernel_saxpy_naive, 4, saxpy_dst_0);
	checkOpenCLErrors(err, "Failed to set args in saxpy_naive kernel");

        err = clEnqueueNDRangeKernel(
                cmdQueue,
                kernel_saxpy_naive,
                1,
                0, &globalSize, &localSize,
                0, 0, 0
        );
        checkOpenCLErrors(err, "Failed at clEnqueueNDRangeKernel");

	// Map SVM buffers
	size_t glbSizeBytes = glbSize * sizeof(float);
	err  = clEnqueueSVMMap(cmdQueue, CL_TRUE, CL_MEM_READ_ONLY, saxpy_dst_0, glbSizeBytes, 0, NULL, NULL);
	checkOpenCLErrors(err, "Failed to map SVM buffers for checking result");

	// Check result
	for (int i = 0; i < glbSize / locSize; ++i)
		printf("%f\n", saxpy_dst_0[i]);

	// Unmap SVM buffers
	err  = clEnqueueSVMUnmap(cmdQueue, saxpy_dst_0, 0, NULL, NULL);
	checkOpenCLErrors(err, "Failed to unmap SVM buffers after checking result");

}

void DynamicParallelism::runStride()
{

}

void DynamicParallelism::runDP()
{

}
int main(int argc, char const *argv[])
{
	std::unique_ptr<DynamicParallelism> dp(new DynamicParallelism());

	printf("Running...\n");

	dp->runNaive();
	dp->runStride();
	dp->runDP();

	printf("Done!\n");

	return 0;
}<commit_msg>update<commit_after>#include "dp.h"

#include <memory>

DynamicParallelism::DynamicParallelism()
{
	runtime  = clRuntime::getInstance();
	file     = clFile::getInstance();

	platform = runtime->getPlatformID();
	device   = runtime->getDevice();
	context  = runtime->getContext();
	cmdQueue = runtime->getCmdQueue(0);

	glbSize = 8192;
	locSize = 256;
	factor  = 2.3f;

	init();
}

DynamicParallelism::~DynamicParallelism()
{
	clean();
}

void DynamicParallelism::init()
{
	initKernel();
	initBuffer();
}

void DynamicParallelism::initKernel()
{
	cl_int err;

	// Open kernel file
        file->open("dp_Kernels.cl");

        // Create program
        const char *source = file->getSourceChar();
        program = clCreateProgramWithSource(context, 1,
                (const char **)&source, NULL, &err);
        checkOpenCLErrors(err, "Failed to create Program with source\n");

        // Create program with OpenCL 2.0 support
        err = clBuildProgram(program, 0, NULL, "-I. -cl-std=CL2.0", NULL, NULL);
        checkOpenCLErrors(err, "Failed to build program...\n");

        // Create kernels
        kernel_saxpy_naive = clCreateKernel(program, "saxpy_naive", &err);
        checkOpenCLErrors(err, "Failed to create saxpy_naive kernel");
        kernel_saxpy_stride = clCreateKernel(program, "saxpy_stride", &err);
        checkOpenCLErrors(err, "Failed to create saxpy_stride kernel");
        kernel_saxpy_dp = clCreateKernel(program, "saxpy_dp", &err);
        checkOpenCLErrors(err, "Failed to create saxpy_dp kernel");
}

void DynamicParallelism::initBuffer()
{
	cl_int err;
	size_t glbSizeBytes = glbSize * sizeof(float);

	saxpy_src_0 = (float *)clSVMAlloc(context, CL_MEM_READ_ONLY, glbSizeBytes, 0);
	saxpy_src_1 = (float *)clSVMAlloc(context, CL_MEM_READ_ONLY, glbSizeBytes, 0);
	saxpy_dst_0 = (float *)clSVMAlloc(context, CL_MEM_READ_WRITE, glbSizeBytes, 0);

	float two = 2.0f;
	float three = 3.0f;

	err  = clEnqueueSVMMemFill(cmdQueue, saxpy_src_0, (const void *)&two, sizeof(float), glbSizeBytes, 0, NULL, NULL);
	err |= clEnqueueSVMMemFill(cmdQueue, saxpy_src_1, (const void *)&three, sizeof(float), glbSizeBytes, 0, NULL, NULL);
	checkOpenCLErrors(err, "Failed to fill SVM buffers");

	err = clFlush(cmdQueue);
	checkOpenCLErrors(err, "Failed to clFlush cmdQueue");

}

void DynamicParallelism::clean()
{
	cleanKernel();
	cleanBuffer();
}

void DynamicParallelism::cleanKernel()
{
	cl_int err;

	err = clReleaseKernel(kernel_saxpy_naive);
	err |= clReleaseKernel(kernel_saxpy_stride);
	err |= clReleaseKernel(kernel_saxpy_dp);
	checkOpenCLErrors(err, "Failed to release kernels");

	err = clReleaseProgram(program);
	checkOpenCLErrors(err, "Failed to release program");
}

void DynamicParallelism::cleanBuffer()
{
	clSVMFreeSafe(context, saxpy_src_0);
	clSVMFreeSafe(context, saxpy_src_1);
	clSVMFreeSafe(context, saxpy_dst_0);
}

void DynamicParallelism::runNaive()
{
	cl_int err;

	size_t globalSize[1] = {(size_t)glbSize};
	size_t localSize[1]  = {(size_t)locSize};

	err  = clSetKernelArg(kernel_saxpy_naive, 0, sizeof(int), (void *)&glbSize);
	err |= clSetKernelArg(kernel_saxpy_naive, 1, sizeof(int), (void *)&factor);
	err |= clSetKernelArgSVMPointer(kernel_saxpy_naive, 2, saxpy_src_0);
	err |= clSetKernelArgSVMPointer(kernel_saxpy_naive, 3, saxpy_src_1);
	err |= clSetKernelArgSVMPointer(kernel_saxpy_naive, 4, saxpy_dst_0);
	checkOpenCLErrors(err, "Failed to set args in saxpy_naive kernel");

        err = clEnqueueNDRangeKernel(
                cmdQueue,
                kernel_saxpy_naive,
                1,
                0, globalSize, localSize,
                0, 0, 0
        );
        checkOpenCLErrors(err, "Failed at clEnqueueNDRangeKernel");

	// Map SVM buffers
	size_t glbSizeBytes = glbSize * sizeof(float);
	err  = clEnqueueSVMMap(cmdQueue, CL_TRUE, CL_MEM_READ_ONLY, saxpy_dst_0, glbSizeBytes, 0, NULL, NULL);
	checkOpenCLErrors(err, "Failed to map SVM buffers for checking result");

	// Check result
	for (int i = 0; i < glbSize / locSize; ++i)
		printf("%f\n", saxpy_dst_0[i]);

	// Unmap SVM buffers
	err  = clEnqueueSVMUnmap(cmdQueue, saxpy_dst_0, 0, NULL, NULL);
	checkOpenCLErrors(err, "Failed to unmap SVM buffers after checking result");

}

void DynamicParallelism::runStride()
{

}

void DynamicParallelism::runDP()
{

}
int main(int argc, char const *argv[])
{
	std::unique_ptr<DynamicParallelism> dp(new DynamicParallelism());

	printf("Running...\n");

	dp->runNaive();
	dp->runStride();
	dp->runDP();

	printf("Done!\n");

	return 0;
}<|endoftext|>


<commit_before><commit_msg>check returned value of PyUnicode_AsUTF8() before passing to a std::string to avoid possible segfaults<commit_after><|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include "xerecord.hxx"
#include "xeroot.hxx"

using namespace ::oox;

// Base classes to export Excel records =======================================

XclExpRecordBase::~XclExpRecordBase()
{
}

void XclExpRecordBase::Save( XclExpStream& /*rStrm*/ )
{
}

void XclExpRecordBase::SaveXml( XclExpXmlStream& /*rStrm*/ )
{
}

// ----------------------------------------------------------------------------

XclExpDelegatingRecord::XclExpDelegatingRecord( XclExpRecordBase* pRecord ) :
    mpRecord( pRecord )
{
}

XclExpDelegatingRecord::~XclExpDelegatingRecord()
{
    // Do Nothing; we use Delegating Record for other objects we "know" will
    // survive...
}

void XclExpDelegatingRecord::SaveXml( XclExpXmlStream& rStrm )
{
    if( mpRecord )
        mpRecord->SaveXml( rStrm );
}

// ----------------------------------------------------------------------------

XclExpXmlElementRecord::XclExpXmlElementRecord(sal_Int32 const nElement)
    : mnElement( nElement )
{
}

XclExpXmlElementRecord::~XclExpXmlElementRecord()
{
}

// ----------------------------------------------------------------------------

XclExpXmlStartElementRecord::XclExpXmlStartElementRecord(sal_Int32 const nElement)
    : XclExpXmlElementRecord(nElement)
{
}

XclExpXmlStartElementRecord::~XclExpXmlStartElementRecord()
{
}

void XclExpXmlStartElementRecord::SaveXml( XclExpXmlStream& rStrm )
{
    sax_fastparser::FSHelperPtr& rStream = rStrm.GetCurrentStream();
    // TODO: no generic way to add attributes here, but it appears to
    // not be needed yet
    rStream->startElement( mnElement, FSEND );
}

// ----------------------------------------------------------------------------

XclExpXmlEndElementRecord::XclExpXmlEndElementRecord( sal_Int32 nElement )
    : XclExpXmlElementRecord( nElement )
{
}

XclExpXmlEndElementRecord::~XclExpXmlEndElementRecord()
{
}

void XclExpXmlEndElementRecord::SaveXml( XclExpXmlStream& rStrm )
{
    rStrm.GetCurrentStream()->endElement( mnElement );
}

// ----------------------------------------------------------------------------

XclExpXmlStartSingleElementRecord::XclExpXmlStartSingleElementRecord(
            sal_Int32 const nElement)
    : XclExpXmlElementRecord( nElement )
{
}

XclExpXmlStartSingleElementRecord::~XclExpXmlStartSingleElementRecord()
{
}

void XclExpXmlStartSingleElementRecord::SaveXml( XclExpXmlStream& rStrm )
{
    sax_fastparser::FSHelperPtr& rStream = rStrm.GetCurrentStream();
    rStream->write( "<" )->writeId( mnElement );
}

// ----------------------------------------------------------------------------

XclExpXmlEndSingleElementRecord::XclExpXmlEndSingleElementRecord()
{
}

XclExpXmlEndSingleElementRecord::~XclExpXmlEndSingleElementRecord()
{
}

void XclExpXmlEndSingleElementRecord::SaveXml( XclExpXmlStream& rStrm )
{
    rStrm.GetCurrentStream()->write( "/>" );
}

// ----------------------------------------------------------------------------

XclExpRecord::XclExpRecord( sal_uInt16 nRecId, sal_Size nRecSize ) :
    mnRecSize( nRecSize ),
    mnRecId( nRecId )
{
}

XclExpRecord::~XclExpRecord()
{
}

void XclExpRecord::SetRecHeader( sal_uInt16 nRecId, sal_Size nRecSize )
{
    SetRecId( nRecId );
    SetRecSize( nRecSize );
}

void XclExpRecord::WriteBody( XclExpStream& /*rStrm*/ )
{
}

void XclExpRecord::Save( XclExpStream& rStrm )
{
    OSL_ENSURE( mnRecId != EXC_ID_UNKNOWN, "XclExpRecord::Save - record ID uninitialized" );
    rStrm.StartRecord( mnRecId, mnRecSize );
    WriteBody( rStrm );
    rStrm.EndRecord();
}

// ----------------------------------------------------------------------------

template<>
void XclExpValueRecord<double>::SaveXml( XclExpXmlStream& rStrm )
{
    if( mnAttribute == -1 )
        return;
    rStrm.WriteAttributes(
        mnAttribute,    OString::number( maValue ).getStr(),
        FSEND );
}

// ----------------------------------------------------------------------------

void XclExpBoolRecord::WriteBody( XclExpStream& rStrm )
{
    rStrm << static_cast< sal_uInt16 >( mbValue ? 1 : 0 );
}

void XclExpBoolRecord::SaveXml( XclExpXmlStream& rStrm )
{
    if( mnAttribute == -1 )
        return;

    rStrm.WriteAttributes(
            // HACK: HIDEOBJ (excdoc.cxx) should be its own object to handle XML_showObjects
            mnAttribute, mnAttribute == XML_showObjects ? "all" : XclXmlUtils::ToPsz( mbValue ),
            FSEND );
}

// ----------------------------------------------------------------------------

XclExpDummyRecord::XclExpDummyRecord( sal_uInt16 nRecId, const void* pRecData, sal_Size nRecSize ) :
    XclExpRecord( nRecId )
{
    SetData( pRecData, nRecSize );
}

void XclExpDummyRecord::SetData( const void* pRecData, sal_Size nRecSize )
{
    mpData = pRecData;
    SetRecSize( pRecData ? nRecSize : 0 );
}

void XclExpDummyRecord::WriteBody( XclExpStream& rStrm )
{
    rStrm.Write( mpData, GetRecSize() );
}

// Future records =============================================================

XclExpFutureRecord::XclExpFutureRecord( XclFutureRecType eRecType, sal_uInt16 nRecId, sal_Size nRecSize ) :
    XclExpRecord( nRecId, nRecSize ),
    meRecType( eRecType )
{
}

void XclExpFutureRecord::Save( XclExpStream& rStrm )
{
    rStrm.StartRecord( GetRecId(), GetRecSize() + ((meRecType == EXC_FUTUREREC_UNUSEDREF) ? 12 : 4) );
    rStrm << GetRecId() << sal_uInt16( 0 );
    if( meRecType == EXC_FUTUREREC_UNUSEDREF )
        rStrm.WriteZeroBytes( 8 );
    WriteBody( rStrm );
    rStrm.EndRecord();
}

// ============================================================================

XclExpSubStream::XclExpSubStream( sal_uInt16 nSubStrmType ) :
    mnSubStrmType( nSubStrmType )
{
}

void XclExpSubStream::Save( XclExpStream& rStrm )
{
    // BOF record
    switch( rStrm.GetRoot().GetBiff() )
    {
        case EXC_BIFF2:
            rStrm.StartRecord( EXC_ID2_BOF, 4 );
            rStrm << sal_uInt16( 7 ) << mnSubStrmType;
            rStrm.EndRecord();
        break;
        case EXC_BIFF3:
            rStrm.StartRecord( EXC_ID3_BOF, 6 );
            rStrm << sal_uInt16( 0 ) << mnSubStrmType << sal_uInt16( 2104 );
            rStrm.EndRecord();
        break;
        case EXC_BIFF4:
            rStrm.StartRecord( EXC_ID4_BOF, 6 );
            rStrm << sal_uInt16( 0 ) << mnSubStrmType << sal_uInt16( 1705 );
            rStrm.EndRecord();
        break;
        case EXC_BIFF5:
            rStrm.StartRecord( EXC_ID5_BOF, 8 );
            rStrm << EXC_BOF_BIFF5 << mnSubStrmType << sal_uInt16( 4915 ) << sal_uInt16( 1994 );
            rStrm.EndRecord();
        break;
        case EXC_BIFF8:
            rStrm.StartRecord( EXC_ID5_BOF, 16 );
            rStrm << EXC_BOF_BIFF8 << mnSubStrmType << sal_uInt16( 3612 ) << sal_uInt16( 1996 );
            rStrm << sal_uInt32( 1 ) << sal_uInt32( 6 );
            rStrm.EndRecord();
        break;
        default:
            DBG_ERROR_BIFF();
    }

    // substream records
    XclExpRecordList<>::Save( rStrm );

    // EOF record
    rStrm.StartRecord( EXC_ID_EOF, 0 );
    rStrm.EndRecord();
}

// ============================================================================

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>cppcheck: Clarify calculation precedence for '<<' and '?'<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include "xerecord.hxx"
#include "xeroot.hxx"

using namespace ::oox;

// Base classes to export Excel records =======================================

XclExpRecordBase::~XclExpRecordBase()
{
}

void XclExpRecordBase::Save( XclExpStream& /*rStrm*/ )
{
}

void XclExpRecordBase::SaveXml( XclExpXmlStream& /*rStrm*/ )
{
}

// ----------------------------------------------------------------------------

XclExpDelegatingRecord::XclExpDelegatingRecord( XclExpRecordBase* pRecord ) :
    mpRecord( pRecord )
{
}

XclExpDelegatingRecord::~XclExpDelegatingRecord()
{
    // Do Nothing; we use Delegating Record for other objects we "know" will
    // survive...
}

void XclExpDelegatingRecord::SaveXml( XclExpXmlStream& rStrm )
{
    if( mpRecord )
        mpRecord->SaveXml( rStrm );
}

// ----------------------------------------------------------------------------

XclExpXmlElementRecord::XclExpXmlElementRecord(sal_Int32 const nElement)
    : mnElement( nElement )
{
}

XclExpXmlElementRecord::~XclExpXmlElementRecord()
{
}

// ----------------------------------------------------------------------------

XclExpXmlStartElementRecord::XclExpXmlStartElementRecord(sal_Int32 const nElement)
    : XclExpXmlElementRecord(nElement)
{
}

XclExpXmlStartElementRecord::~XclExpXmlStartElementRecord()
{
}

void XclExpXmlStartElementRecord::SaveXml( XclExpXmlStream& rStrm )
{
    sax_fastparser::FSHelperPtr& rStream = rStrm.GetCurrentStream();
    // TODO: no generic way to add attributes here, but it appears to
    // not be needed yet
    rStream->startElement( mnElement, FSEND );
}

// ----------------------------------------------------------------------------

XclExpXmlEndElementRecord::XclExpXmlEndElementRecord( sal_Int32 nElement )
    : XclExpXmlElementRecord( nElement )
{
}

XclExpXmlEndElementRecord::~XclExpXmlEndElementRecord()
{
}

void XclExpXmlEndElementRecord::SaveXml( XclExpXmlStream& rStrm )
{
    rStrm.GetCurrentStream()->endElement( mnElement );
}

// ----------------------------------------------------------------------------

XclExpXmlStartSingleElementRecord::XclExpXmlStartSingleElementRecord(
            sal_Int32 const nElement)
    : XclExpXmlElementRecord( nElement )
{
}

XclExpXmlStartSingleElementRecord::~XclExpXmlStartSingleElementRecord()
{
}

void XclExpXmlStartSingleElementRecord::SaveXml( XclExpXmlStream& rStrm )
{
    sax_fastparser::FSHelperPtr& rStream = rStrm.GetCurrentStream();
    rStream->write( "<" )->writeId( mnElement );
}

// ----------------------------------------------------------------------------

XclExpXmlEndSingleElementRecord::XclExpXmlEndSingleElementRecord()
{
}

XclExpXmlEndSingleElementRecord::~XclExpXmlEndSingleElementRecord()
{
}

void XclExpXmlEndSingleElementRecord::SaveXml( XclExpXmlStream& rStrm )
{
    rStrm.GetCurrentStream()->write( "/>" );
}

// ----------------------------------------------------------------------------

XclExpRecord::XclExpRecord( sal_uInt16 nRecId, sal_Size nRecSize ) :
    mnRecSize( nRecSize ),
    mnRecId( nRecId )
{
}

XclExpRecord::~XclExpRecord()
{
}

void XclExpRecord::SetRecHeader( sal_uInt16 nRecId, sal_Size nRecSize )
{
    SetRecId( nRecId );
    SetRecSize( nRecSize );
}

void XclExpRecord::WriteBody( XclExpStream& /*rStrm*/ )
{
}

void XclExpRecord::Save( XclExpStream& rStrm )
{
    OSL_ENSURE( mnRecId != EXC_ID_UNKNOWN, "XclExpRecord::Save - record ID uninitialized" );
    rStrm.StartRecord( mnRecId, mnRecSize );
    WriteBody( rStrm );
    rStrm.EndRecord();
}

// ----------------------------------------------------------------------------

template<>
void XclExpValueRecord<double>::SaveXml( XclExpXmlStream& rStrm )
{
    if( mnAttribute == -1 )
        return;
    rStrm.WriteAttributes(
        mnAttribute,    OString::number( maValue ).getStr(),
        FSEND );
}

// ----------------------------------------------------------------------------

void XclExpBoolRecord::WriteBody( XclExpStream& rStrm )
{
    rStrm << (static_cast< sal_uInt16 >( mbValue ? 1 : 0 ));
}

void XclExpBoolRecord::SaveXml( XclExpXmlStream& rStrm )
{
    if( mnAttribute == -1 )
        return;

    rStrm.WriteAttributes(
            // HACK: HIDEOBJ (excdoc.cxx) should be its own object to handle XML_showObjects
            mnAttribute, mnAttribute == XML_showObjects ? "all" : XclXmlUtils::ToPsz( mbValue ),
            FSEND );
}

// ----------------------------------------------------------------------------

XclExpDummyRecord::XclExpDummyRecord( sal_uInt16 nRecId, const void* pRecData, sal_Size nRecSize ) :
    XclExpRecord( nRecId )
{
    SetData( pRecData, nRecSize );
}

void XclExpDummyRecord::SetData( const void* pRecData, sal_Size nRecSize )
{
    mpData = pRecData;
    SetRecSize( pRecData ? nRecSize : 0 );
}

void XclExpDummyRecord::WriteBody( XclExpStream& rStrm )
{
    rStrm.Write( mpData, GetRecSize() );
}

// Future records =============================================================

XclExpFutureRecord::XclExpFutureRecord( XclFutureRecType eRecType, sal_uInt16 nRecId, sal_Size nRecSize ) :
    XclExpRecord( nRecId, nRecSize ),
    meRecType( eRecType )
{
}

void XclExpFutureRecord::Save( XclExpStream& rStrm )
{
    rStrm.StartRecord( GetRecId(), GetRecSize() + ((meRecType == EXC_FUTUREREC_UNUSEDREF) ? 12 : 4) );
    rStrm << GetRecId() << sal_uInt16( 0 );
    if( meRecType == EXC_FUTUREREC_UNUSEDREF )
        rStrm.WriteZeroBytes( 8 );
    WriteBody( rStrm );
    rStrm.EndRecord();
}

// ============================================================================

XclExpSubStream::XclExpSubStream( sal_uInt16 nSubStrmType ) :
    mnSubStrmType( nSubStrmType )
{
}

void XclExpSubStream::Save( XclExpStream& rStrm )
{
    // BOF record
    switch( rStrm.GetRoot().GetBiff() )
    {
        case EXC_BIFF2:
            rStrm.StartRecord( EXC_ID2_BOF, 4 );
            rStrm << sal_uInt16( 7 ) << mnSubStrmType;
            rStrm.EndRecord();
        break;
        case EXC_BIFF3:
            rStrm.StartRecord( EXC_ID3_BOF, 6 );
            rStrm << sal_uInt16( 0 ) << mnSubStrmType << sal_uInt16( 2104 );
            rStrm.EndRecord();
        break;
        case EXC_BIFF4:
            rStrm.StartRecord( EXC_ID4_BOF, 6 );
            rStrm << sal_uInt16( 0 ) << mnSubStrmType << sal_uInt16( 1705 );
            rStrm.EndRecord();
        break;
        case EXC_BIFF5:
            rStrm.StartRecord( EXC_ID5_BOF, 8 );
            rStrm << EXC_BOF_BIFF5 << mnSubStrmType << sal_uInt16( 4915 ) << sal_uInt16( 1994 );
            rStrm.EndRecord();
        break;
        case EXC_BIFF8:
            rStrm.StartRecord( EXC_ID5_BOF, 16 );
            rStrm << EXC_BOF_BIFF8 << mnSubStrmType << sal_uInt16( 3612 ) << sal_uInt16( 1996 );
            rStrm << sal_uInt32( 1 ) << sal_uInt32( 6 );
            rStrm.EndRecord();
        break;
        default:
            DBG_ERROR_BIFF();
    }

    // substream records
    XclExpRecordList<>::Save( rStrm );

    // EOF record
    rStrm.StartRecord( EXC_ID_EOF, 0 );
    rStrm.EndRecord();
}

// ============================================================================

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>#ifndef MJOLNIR_SCALAR_TYPE_OF
#define MJOLNIR_SCALAR_TYPE_OF
#include <array>

namespace mjolnir
{

template<typename T>
struct scalar_type_of{};

template<typename T>
struct scalar_type_of<std::array<T>> {typedef T type;};

template<typename T, std::size_t N>
struct scalar_type_of<T[N]> {typedef T type;};

template<typename T>
using scalar_type = typename scalar_type_of<T>::type;

}// mjolnir

#endif /* MJOLNIR_SCALAR_TYPE_OF */
<commit_msg>fix partial specialization argument<commit_after>#ifndef MJOLNIR_SCALAR_TYPE_OF
#define MJOLNIR_SCALAR_TYPE_OF
#include <array>

namespace mjolnir
{

template<typename T>
struct scalar_type_of{};

template<typename T, std::size_t N>
struct scalar_type_of<std::array<T, N>> {typedef T type;};

template<typename T, std::size_t N>
struct scalar_type_of<T[N]> {typedef T type;};

template<typename T>
using scalar_type = typename scalar_type_of<T>::type;

}// mjolnir

#endif /* MJOLNIR_SCALAR_TYPE_OF */
<|endoftext|>


<commit_before>//!
//! @file   MechanicTranslationalMassWithLever.hpp
//! @author Björn Eriksson <bjorn.eriksson@liu.se>
//! @date   2011-03-11
//!
//! @brief Contains a Lever with a Mass
//!
//$Id$

#ifndef MECHANICTRANSLATIONALMASSWITHLEVER_HPP_INCLUDED
#define MECHANICTRANSLATIONALMASSWITHLEVER_HPP_INCLUDED

#include <sstream>

#include "ComponentEssentials.h"
#include "ComponentUtilities.h"

namespace hopsan {

    //Verified with AMESim 2011-03-21
    //!
    //! @brief
    //! @ingroup MechanicalComponents
    //!
    class MechanicTranslationalMassWithLever : public ComponentQ
    {

    private:
        double L1, L2, w, m, B;
        double *mpND_f1, *mpND_x1, *mpND_v1, *mpND_me1, *mpND_c1, *mpND_Zx1,
               *mpND_f2, *mpND_x2, *mpND_v2, *mpND_me2, *mpND_c2, *mpND_Zx2;  //Node data pointers
        double f1, x1, v1, c1, Zx1,
               f2, x2, v2, c2, Zx2; //Node data variables
        double mNum[3];
        double mDen[3];
        DoubleIntegratorWithDamping mIntegrator;
        Port *mpP1, *mpP2;

    public:
        static Component *Creator()
        {
            return new MechanicTranslationalMassWithLever();
        }

        MechanicTranslationalMassWithLever() : ComponentQ()
        {
            //! @todo set eqmass to some good values, should consider lever.

            //Set member attributes
            L1 = 1;
            L2 = 1;
            m = 1.0;
            B = 10;
            w = 1.0;

            //Add ports to the component
            mpP1 = addPowerPort("P1", "NodeMechanic");
            mpP2 = addPowerPort("P2", "NodeMechanic");

            //Register changable parameters to the HOPSAN++ core
            registerParameter("L_1", "Length", "[m]",               L1);
            registerParameter("L_2", "Length", "[m]",               L2);
            registerParameter("m",  "Mass", "[kg]",                m);
            registerParameter("B",  "Viscous Friction", "[Ns/m]",  B);
        }

        void initialize()
        {
            //Assign node data pointers
            mpND_f1  = getSafeNodeDataPtr(mpP1, NodeMechanic::FORCE);
            mpND_x1  = getSafeNodeDataPtr(mpP1, NodeMechanic::POSITION);
            mpND_v1  = getSafeNodeDataPtr(mpP1, NodeMechanic::VELOCITY);
            mpND_me1 = getSafeNodeDataPtr(mpP1, NodeMechanic::EQMASS);
            mpND_c1  = getSafeNodeDataPtr(mpP1, NodeMechanic::WAVEVARIABLE);
            mpND_Zx1 = getSafeNodeDataPtr(mpP1, NodeMechanic::CHARIMP);

            mpND_f2  = getSafeNodeDataPtr(mpP2, NodeMechanic::FORCE);
            mpND_x2  = getSafeNodeDataPtr(mpP2, NodeMechanic::POSITION);
            mpND_v2  = getSafeNodeDataPtr(mpP2, NodeMechanic::VELOCITY);
            mpND_me2 = getSafeNodeDataPtr(mpP2, NodeMechanic::EQMASS);
            mpND_c2  = getSafeNodeDataPtr(mpP2, NodeMechanic::WAVEVARIABLE);
            mpND_Zx2 = getSafeNodeDataPtr(mpP2, NodeMechanic::CHARIMP);

            //Initialization
            f1 = (*mpND_f1);
            f2 = (*mpND_f2);
            x1 = (*mpND_x1);
            v2 = (*mpND_v1);

            w = (L1+L2)/L1;

            mIntegrator.initialize(mTimestep, 0, (f1-f2)/m, -x1/w, -v1/w);

            //Print debug message if velocities do not match
            if(mpP1->readNode(NodeMechanic::VELOCITY)*w != -mpP2->readNode(NodeMechanic::VELOCITY))
            {
                std::stringstream ss;
                ss << "Start velocities does not match, {" << getName() << "::" << mpP1->getPortName() <<
                        "} and {" << getName() << "::" << mpP2->getPortName() << "}.";
                this->addDebugMessage(ss.str());
            }

            (*mpND_me1) = m*w;
            (*mpND_me2) = m;
        }

        void simulateOneTimestep()
        {
            //Get variable values from nodes
            c1 = (*mpND_c1)/w;
            Zx1 = (*mpND_Zx1)/pow(w, 2.0);
            c2 = (*mpND_c2);
            Zx2 = (*mpND_Zx2);

            //Mass equations
            mIntegrator.setDamping((B+Zx1+Zx2) / m * mTimestep);
            mIntegrator.integrateWithUndo((c1-c2)/m);
            v2 = mIntegrator.valueFirst();
            x2 = mIntegrator.valueSecond();
            v1 = -v2/w;
            x1 = -x2/w;
            f1 = (c1 - Zx1*v2)*w;
            f2 = c2 + Zx2*v2;

            //Write new values to nodes
            (*mpND_f1) = f1;
            (*mpND_x1) = x1;
            (*mpND_v1) = v1;
            (*mpND_me1) = m*w;
            (*mpND_f2) = f2;
            (*mpND_x2) = x2;
            (*mpND_v2) = v2;
            (*mpND_me2) = m;
        }
    };
}

#endif // MECHANICTRANSLATIONALMASSWITHLEVER_HPP_INCLUDED

<commit_msg>Fixed Bug #465<commit_after>//!
//! @file   MechanicTranslationalMassWithLever.hpp
//! @author Björn Eriksson <bjorn.eriksson@liu.se>
//! @date   2011-03-11
//!
//! @brief Contains a Lever with a Mass
//!
//$Id$

#ifndef MECHANICTRANSLATIONALMASSWITHLEVER_HPP_INCLUDED
#define MECHANICTRANSLATIONALMASSWITHLEVER_HPP_INCLUDED

#include <sstream>

#include "ComponentEssentials.h"
#include "ComponentUtilities.h"

namespace hopsan {

    //Verified with another simulation software 2011-03-21
    //!
    //! @brief
    //! @ingroup MechanicalComponents
    //!
    class MechanicTranslationalMassWithLever : public ComponentQ
    {

    private:
        double L1, L2, w, m, B;
        double *mpND_f1, *mpND_x1, *mpND_v1, *mpND_me1, *mpND_c1, *mpND_Zx1,
               *mpND_f2, *mpND_x2, *mpND_v2, *mpND_me2, *mpND_c2, *mpND_Zx2;  //Node data pointers
        double f1, x1, v1, c1, Zx1,
               f2, x2, v2, c2, Zx2; //Node data variables
        double mNum[3];
        double mDen[3];
        DoubleIntegratorWithDamping mIntegrator;
        Port *mpP1, *mpP2;

    public:
        static Component *Creator()
        {
            return new MechanicTranslationalMassWithLever();
        }

        MechanicTranslationalMassWithLever() : ComponentQ()
        {
            //! @todo set eqmass to some good values, should consider lever.

            //Set member attributes
            L1 = 1;
            L2 = 1;
            m = 1.0;
            B = 10;
            w = 1.0;

            //Add ports to the component
            mpP1 = addPowerPort("P1", "NodeMechanic");
            mpP2 = addPowerPort("P2", "NodeMechanic");

            //Register changable parameters to the HOPSAN++ core
            registerParameter("L_1", "Length", "[m]",               L1);
            registerParameter("L_2", "Length", "[m]",               L2);
            registerParameter("m",  "Mass", "[kg]",                m);
            registerParameter("B",  "Viscous Friction", "[Ns/m]",  B);
        }

        void initialize()
        {
            //Assign node data pointers
            mpND_f1  = getSafeNodeDataPtr(mpP1, NodeMechanic::FORCE);
            mpND_x1  = getSafeNodeDataPtr(mpP1, NodeMechanic::POSITION);
            mpND_v1  = getSafeNodeDataPtr(mpP1, NodeMechanic::VELOCITY);
            mpND_me1 = getSafeNodeDataPtr(mpP1, NodeMechanic::EQMASS);
            mpND_c1  = getSafeNodeDataPtr(mpP1, NodeMechanic::WAVEVARIABLE);
            mpND_Zx1 = getSafeNodeDataPtr(mpP1, NodeMechanic::CHARIMP);

            mpND_f2  = getSafeNodeDataPtr(mpP2, NodeMechanic::FORCE);
            mpND_x2  = getSafeNodeDataPtr(mpP2, NodeMechanic::POSITION);
            mpND_v2  = getSafeNodeDataPtr(mpP2, NodeMechanic::VELOCITY);
            mpND_me2 = getSafeNodeDataPtr(mpP2, NodeMechanic::EQMASS);
            mpND_c2  = getSafeNodeDataPtr(mpP2, NodeMechanic::WAVEVARIABLE);
            mpND_Zx2 = getSafeNodeDataPtr(mpP2, NodeMechanic::CHARIMP);

            //Initialization
            f1 = (*mpND_f1);
            f2 = (*mpND_f2);
            x1 = (*mpND_x1);
            v1 = (*mpND_v1);

            w = (L1+L2)/L1;

            mIntegrator.initialize(mTimestep, 0, (f1-f2)/m, -x1*w, -v1*w);
            (*mpND_x2) = -x1*w;
            (*mpND_v2) = -v1*w;

            //Print debug message if velocities do not match
            if(mpP1->readNode(NodeMechanic::VELOCITY)*w != -mpP2->readNode(NodeMechanic::VELOCITY))
            {
                std::stringstream ss;
                ss << "Start velocities does not match, {" << getName() << "::" << mpP1->getPortName() <<
                        "} and {" << getName() << "::" << mpP2->getPortName() << "}.";
                this->addDebugMessage(ss.str());
            }

            (*mpND_me1) = m*w;
            (*mpND_me2) = m;
        }

        void simulateOneTimestep()
        {
            //Get variable values from nodes
            c1 = (*mpND_c1)/w;
            Zx1 = (*mpND_Zx1)/pow(w, 2.0);
            c2 = (*mpND_c2);
            Zx2 = (*mpND_Zx2);

            //Mass equations
            mIntegrator.setDamping((B+Zx1+Zx2) / m * mTimestep);
            mIntegrator.integrateWithUndo((c1-c2)/m);
            v2 = mIntegrator.valueFirst();
            x2 = mIntegrator.valueSecond();
            v1 = -v2/w;
            x1 = -x2/w;
            f1 = (c1 - Zx1*v2)*w;
            f2 = c2 + Zx2*v2;

            //Write new values to nodes
            (*mpND_f1) = f1;
            (*mpND_x1) = x1;
            (*mpND_v1) = v1;
            (*mpND_me1) = m*w;
            (*mpND_f2) = f2;
            (*mpND_x2) = x2;
            (*mpND_v2) = v2;
            (*mpND_me2) = m;
        }
    };
}

#endif // MECHANICTRANSLATIONALMASSWITHLEVER_HPP_INCLUDED

<|endoftext|>


<commit_before>#include <string.h>

#include "Blur.h"
#include "kernels/blur.h"

#include <CL/cl.h>

namespace improsa
{
  Blur::Blur() : Filter()
  {
    m_name = "Blur";
  }

  bool Blur::runHalideCPU(Image input, Image output)
  {
    reportStatus("runHalideCPU not implemented");
    return false;
  }

  bool Blur::runHalideGPU(Image input, Image output)
  {
    reportStatus("runHalideGPU not implemented");
    return false;
  }

  bool Blur::runOpenCL(Image input, Image output)
  {
    if (!initCL(blur_kernel))
    {
      return false;
    }

    cl_int err;
    cl_kernel kernel;
    cl_mem d_input, d_output;
    cl_image_format format = {CL_RGBA, CL_UNORM_INT8};

    kernel = clCreateKernel(m_program, "blur", &err);
    CHECK_ERROR_OCL(err, "creating kernel", return false);

    d_input = clCreateImage2D(
      m_context, CL_MEM_READ_ONLY, &format,
      input.width, input.height, 0, NULL, &err);
    CHECK_ERROR_OCL(err, "creating input image", return false);

    d_output = clCreateImage2D(
      m_context, CL_MEM_WRITE_ONLY, &format,
      input.width, input.height, 0, NULL, &err);
    CHECK_ERROR_OCL(err, "creating output image", return false);

    size_t origin[3] = {0, 0, 0};
    size_t region[3] = {input.width, input.height, 1};
    err = clEnqueueWriteImage(
      m_queue, d_input, CL_TRUE,
      origin, region, 0, 0, input.data, 0, NULL, NULL);
    CHECK_ERROR_OCL(err, "writing image data", return false);

    err  = clSetKernelArg(kernel, 0, sizeof(cl_mem), &d_input);
    err |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &d_output);
    CHECK_ERROR_OCL(err, "setting kernel arguments", return false);

    reportStatus("Running OpenCL kernel");

    double start = getCurrentTime();

    size_t global[2] = {output.width, output.height};
    err = clEnqueueNDRangeKernel(
      m_queue, kernel, 2, NULL, global, NULL, 0, NULL, NULL);
    CHECK_ERROR_OCL(err, "enqueuing kernel", return false);

    err = clFinish(m_queue);
    CHECK_ERROR_OCL(err, "running kernel", return false);

    double end = getCurrentTime();

    reportStatus("Finished OpenCL kernel");

    err = clEnqueueReadImage(
      m_queue, d_output, CL_TRUE,
      origin, region, 0, 0, output.data, 0, NULL, NULL);
    CHECK_ERROR_OCL(err, "reading image data", return false);

    bool passed = verify(input, output);
    reportStatus(
      "Finished in %.1lf ms (verification %s)",
      (end-start)*1e-3, passed ? "passed" : "failed");

    clReleaseMemObject(d_input);
    clReleaseMemObject(d_output);
    clReleaseKernel(kernel);
    releaseCL();
    return passed;
  }

  bool Blur::runReference(Image input, Image output)
  {
    for (int y = 0; y < output.height; y++)
    {
      for (int x = 0; x < output.width; x++)
      {
        int r = 0;
        int g = 0;
        int b = 0;
        for (int j = -1; j <= 1; j++)
        {
          for (int i = -1; i <= 1; i++)
          {
            r += getPixel(input, x+i, y+j, 0);
            g += getPixel(input, x+i, y+j, 1);
            b += getPixel(input, x+i, y+j, 2);
          }
        }
        setPixel(output, x, y, 0, r/9);
        setPixel(output, x, y, 1, g/9);
        setPixel(output, x, y, 2, b/9);
        setPixel(output, x, y, 3, getPixel(input, x, y, 3));
      }
      reportStatus("Completed %.1f%% of reference", (100.f*y)/(input.height-1));
    }
    reportStatus("Finished reference");
    return true;
  }
}
<commit_msg>Blur kernel timed over multiple runs, with warmup.<commit_after>#include <string.h>

#include "Blur.h"
#include "kernels/blur.h"

#include <CL/cl.h>

namespace improsa
{
  Blur::Blur() : Filter()
  {
    m_name = "Blur";
  }

  bool Blur::runHalideCPU(Image input, Image output)
  {
    reportStatus("runHalideCPU not implemented");
    return false;
  }

  bool Blur::runHalideGPU(Image input, Image output)
  {
    reportStatus("runHalideGPU not implemented");
    return false;
  }

  bool Blur::runOpenCL(Image input, Image output)
  {
    if (!initCL(blur_kernel))
    {
      return false;
    }

    cl_int err;
    cl_kernel kernel;
    cl_mem d_input, d_output;
    cl_image_format format = {CL_RGBA, CL_UNORM_INT8};

    kernel = clCreateKernel(m_program, "blur", &err);
    CHECK_ERROR_OCL(err, "creating kernel", return false);

    d_input = clCreateImage2D(
      m_context, CL_MEM_READ_ONLY, &format,
      input.width, input.height, 0, NULL, &err);
    CHECK_ERROR_OCL(err, "creating input image", return false);

    d_output = clCreateImage2D(
      m_context, CL_MEM_WRITE_ONLY, &format,
      input.width, input.height, 0, NULL, &err);
    CHECK_ERROR_OCL(err, "creating output image", return false);

    size_t origin[3] = {0, 0, 0};
    size_t region[3] = {input.width, input.height, 1};
    err = clEnqueueWriteImage(
      m_queue, d_input, CL_TRUE,
      origin, region, 0, 0, input.data, 0, NULL, NULL);
    CHECK_ERROR_OCL(err, "writing image data", return false);

    err  = clSetKernelArg(kernel, 0, sizeof(cl_mem), &d_input);
    err |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &d_output);
    CHECK_ERROR_OCL(err, "setting kernel arguments", return false);

    reportStatus("Running OpenCL kernel");

    size_t global[2] = {output.width, output.height};

    // Timed runs
    int iterations = 8;
    double start = getCurrentTime();
    for (int i = 0; i < iterations + 1; i++)
    {
      err = clEnqueueNDRangeKernel(
        m_queue, kernel, 2, NULL, global, NULL, 0, NULL, NULL);
      CHECK_ERROR_OCL(err, "enqueuing kernel", return false);

      // Start timing after warm-up run
      if (i == 0)
      {
        err = clFinish(m_queue);
        CHECK_ERROR_OCL(err, "running kernel", return false);
        start = getCurrentTime();
      }
    }
    err = clFinish(m_queue);
    CHECK_ERROR_OCL(err, "running kernel", return false);
    double end = getCurrentTime();

    reportStatus("Finished OpenCL kernel");

    err = clEnqueueReadImage(
      m_queue, d_output, CL_TRUE,
      origin, region, 0, 0, output.data, 0, NULL, NULL);
    CHECK_ERROR_OCL(err, "reading image data", return false);

    bool passed = verify(input, output);
    reportStatus(
      "Finished in %.1lf ms (verification %s)",
      (end-start)*1e-3/iterations, passed ? "passed" : "failed");

    clReleaseMemObject(d_input);
    clReleaseMemObject(d_output);
    clReleaseKernel(kernel);
    releaseCL();
    return passed;
  }

  bool Blur::runReference(Image input, Image output)
  {
    for (int y = 0; y < output.height; y++)
    {
      for (int x = 0; x < output.width; x++)
      {
        int r = 0;
        int g = 0;
        int b = 0;
        for (int j = -1; j <= 1; j++)
        {
          for (int i = -1; i <= 1; i++)
          {
            r += getPixel(input, x+i, y+j, 0);
            g += getPixel(input, x+i, y+j, 1);
            b += getPixel(input, x+i, y+j, 2);
          }
        }
        setPixel(output, x, y, 0, r/9);
        setPixel(output, x, y, 1, g/9);
        setPixel(output, x, y, 2, b/9);
        setPixel(output, x, y, 3, getPixel(input, x, y, 3));
      }
      reportStatus("Completed %.1f%% of reference", (100.f*y)/(input.height-1));
    }
    reportStatus("Finished reference");
    return true;
  }
}
<|endoftext|>


<commit_before>
#include "jnif.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <list>
#include <dlfcn.h>
#include <errno.h>

#include "erjang_NIF.h"

/** global data */

static JavaVM *jvm;

static jmethodID m_eobject__testReference;

static jclass    ERT_class;
static jmethodID m_ERT__badarg;

void *enif_alloc(size_t size)
{
  return malloc(size);
}

void enif_free(void *data)
{
  free(data);
}

int enif_is_ref(ErlNifEnv* ee, ERL_NIF_TERM term)
{
  JNIEnv *je = ee->je;
  jobject ok = je->CallObjectMethod((jobject)term, m_eobject__testReference);
  return ok != JVM_NULL;
}

ERL_NIF_TERM enif_make_badarg(ErlNifEnv* env)
{
  return THE_BADARG;
}

int enif_is_exception(ErlNifEnv *env, ERL_NIF_TERM term)
{
  return term == THE_BADARG;
}

typedef ErlNifEntry* (*nif_init_t)();

JNIEXPORT jlong JNICALL Java_erjang_NIF_jni_1load
  (JNIEnv * je, jclass self, jstring library, jobject term)
{
  jboolean isCopy;
  const char *path = je->GetStringUTFChars(library, &isCopy);
  if (path == NULL)
    return 0;
  void * so_handle = dlopen( path, /* RTLD_LAZY | */ RTLD_FIRST);

  if (so_handle == NULL) {
    fprintf(stderr, "did not load %s (err: %i)\n", path, errno);
    je->ReleaseStringUTFChars(library, path);
    return 0;
  }

  je->ReleaseStringUTFChars(library, path);

  void *address =  dlsym( so_handle, "nif_init" );
  if (address == NULL) {
    fprintf(stderr, "did not find nif_init (err: %i)\n", errno);
    dlclose(so_handle);
    return 0L;
  }

  nif_init_t nif_init_fp = reinterpret_cast<nif_init_t>(address);
  ErlNifEntry *entry = (*nif_init_fp)();

  if (entry->major != ERL_NIF_MAJOR_VERSION) {
    // fail
    fprintf(stderr, "bad erl_nif_major_version %i (vs. expected %i)\n",
            entry->major,
            ERL_NIF_MAJOR_VERSION);
    dlclose(so_handle);
    return 0L;
  }

  struct jnif_module *mod = new jnif_module();
  mod->so_handle = so_handle;
  mod->entry = entry;
  mod->priv_data = NULL;
  mod->global = new enif_environment_t();

  // Call the on-load callback. Terms allocated
  // durin onload are retained until we unload.
  jnif_init_env(mod->global, je, mod, enif_environment_t::ALLOC);
  if (entry->load != 0) {
    int success = (*entry->load)( mod->global,
                                  &mod->priv_data,
                                  J2E(term));

    if (success != 0) {
      fprintf(stderr, "%s:load returned %i\n",
              mod->entry->name,
              success);

      dlclose( so_handle );
      jnif_release_env(mod->global);
      delete mod;
      mod = NULL;
    }
  }

  // when nif_init is done, we may need to "commit" data that
  // was made available to the NIF as char* data.
  jnif_commit_env(mod->global);

  // mod->global should be released when unloading
  return reinterpret_cast<jlong>(mod);
}

/*
 * Class:     erjang_NIF
 * Method:    jni_module_name
 * Signature: (J)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_erjang_NIF_jni_1module_1name
  (JNIEnv * je, jclass self, jlong mod_ptr)
{
    struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_ptr);

    return je->NewStringUTF(mod->entry->name);
}

/*
 * Class:     erjang_NIF
 * Method:    jni_fun_count
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_erjang_NIF_jni_1fun_1count
  (JNIEnv * je, jclass self, jlong mod_ptr)
{
    struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_ptr);

    return mod->entry->num_of_funcs;
}

/*
 * Class:     erjang_NIF
 * Method:    jni_fun_name
 * Signature: (JI)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_erjang_NIF_jni_1fun_1name
  (JNIEnv *je, jclass self, jlong mod_ptr, jint idx)
{
    struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_ptr);

    return je->NewStringUTF(mod->entry->funcs[idx].name);
}

/*
 * Class:     erjang_NIF
 * Method:    jni_fun_arity
 * Signature: (JI)I
 */
JNIEXPORT jint JNICALL Java_erjang_NIF_jni_1fun_1arity
  (JNIEnv *je, jclass self, jlong mod_ptr, jint idx)
{
    struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_ptr);

    return mod->entry->funcs[idx].arity;
}

JNIEXPORT jobject JNICALL Java_erjang_NIF_jni_1invoke
   (JNIEnv* je,
    jobject self,
    jobject proc,
    jlong mod_addr,
    jint index,
    jobjectArray args)
{
  struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_addr);

  ErlNifEntry *entry = mod->entry;
  if (index < 0 || index >= entry->num_of_funcs) {
    return NULL;
  }

  ErlNifFunc *func = &entry->funcs[index];
  jint size = je->GetArrayLength(args);

  ERL_NIF_TERM nif_args[size];
  for (int i = 0; i < size; i++) {
    jobject term = je->GetObjectArrayElement(args, i);
    nif_args[i] = (ERL_NIF_TERM)term;
  }

  struct enif_environment_t ee;
  jnif_init_env ( &ee, je, mod, enif_environment_t::STACK );
  ee.self = proc;

  ERL_NIF_TERM result = (*func->fptr)(&ee, size, nif_args);

  jnif_release_env( &ee );

  if (result == THE_BADARG) {
    je->CallStaticObjectMethod( ERT_class, m_ERT__badarg);
    return NULL;
  }

  return (jobject)result;
}

////////////

static void init_jvm_data(JavaVM *vm, JNIEnv* je)
{
  jvm = vm;

  jclass eobject_class      = je->FindClass("erjang/EObject");
  m_eobject__testReference  = je->GetMethodID(eobject_class, "testReference", "()Lerjang/ERef;");

  ERT_class = je->FindClass("erjang/ERT");
  ERT_class = (jclass)je->NewGlobalRef(ERT_class);
  m_ERT__badarg  = je->GetStaticMethodID(ERT_class, "badarg", "()Lerjang/ErlangError;");
}

extern "C" jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
  JNIEnv *je;
  if (vm->AttachCurrentThreadAsDaemon((void**)&je, NULL) == JNI_OK) {
    init_jvm_data(vm, je);
    initialize_jnif_env(vm,je);
    initialize_jnif_binary(vm,je);
    initialize_jnif_resource(vm,je);
    initialize_jnif_string(vm,je);
    initialize_jnif_number(vm,je);
    initialize_jnif_atom(vm,je);
    initialize_jnif_tuple(vm,je);
    initialize_jnif_list(vm, je);
    initialize_jnif_sys(vm, je);
    initialize_jnif_process(vm, je);
  }
  return JNI_VERSION_1_4;
}

extern "C" void JNI_OnUnload(JavaVM *vm, void *reserved)
{
  if (vm == jvm) {
    JNIEnv *je;
    if (vm->AttachCurrentThreadAsDaemon((void**)&je, NULL) == JNI_OK) {
      uninitialize_jnif_binary(vm, je);
    }
    jvm = NULL;
  }
}
<commit_msg>Add enif_realloc NIF API function<commit_after>
#include "jnif.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <list>
#include <dlfcn.h>
#include <errno.h>

#include "erjang_NIF.h"

/** global data */

static JavaVM *jvm;

static jmethodID m_eobject__testReference;

static jclass    ERT_class;
static jmethodID m_ERT__badarg;

void* enif_realloc(void* ptr, size_t size)
{
  return realloc(ptr, size);
}

void *enif_alloc(size_t size)
{
  return malloc(size);
}

void enif_free(void *data)
{
  free(data);
}

int enif_is_ref(ErlNifEnv* ee, ERL_NIF_TERM term)
{
  JNIEnv *je = ee->je;
  jobject ok = je->CallObjectMethod((jobject)term, m_eobject__testReference);
  return ok != JVM_NULL;
}

ERL_NIF_TERM enif_make_badarg(ErlNifEnv* env)
{
  return THE_BADARG;
}

int enif_is_exception(ErlNifEnv *env, ERL_NIF_TERM term)
{
  return term == THE_BADARG;
}

typedef ErlNifEntry* (*nif_init_t)();

JNIEXPORT jlong JNICALL Java_erjang_NIF_jni_1load
  (JNIEnv * je, jclass self, jstring library, jobject term)
{
  jboolean isCopy;
  const char *path = je->GetStringUTFChars(library, &isCopy);
  if (path == NULL)
    return 0;
  void * so_handle = dlopen( path, /* RTLD_LAZY | */ RTLD_FIRST);

  if (so_handle == NULL) {
    fprintf(stderr, "did not load %s (err: %i)\n", path, errno);
    je->ReleaseStringUTFChars(library, path);
    return 0;
  }

  je->ReleaseStringUTFChars(library, path);

  void *address =  dlsym( so_handle, "nif_init" );
  if (address == NULL) {
    fprintf(stderr, "did not find nif_init (err: %i)\n", errno);
    dlclose(so_handle);
    return 0L;
  }

  nif_init_t nif_init_fp = reinterpret_cast<nif_init_t>(address);
  ErlNifEntry *entry = (*nif_init_fp)();

  if (entry->major != ERL_NIF_MAJOR_VERSION) {
    // fail
    fprintf(stderr, "bad erl_nif_major_version %i (vs. expected %i)\n",
            entry->major,
            ERL_NIF_MAJOR_VERSION);
    dlclose(so_handle);
    return 0L;
  }

  struct jnif_module *mod = new jnif_module();
  mod->so_handle = so_handle;
  mod->entry = entry;
  mod->priv_data = NULL;
  mod->global = new enif_environment_t();

  // Call the on-load callback. Terms allocated
  // durin onload are retained until we unload.
  jnif_init_env(mod->global, je, mod, enif_environment_t::ALLOC);
  if (entry->load != 0) {
    int success = (*entry->load)( mod->global,
                                  &mod->priv_data,
                                  J2E(term));

    if (success != 0) {
      fprintf(stderr, "%s:load returned %i\n",
              mod->entry->name,
              success);

      dlclose( so_handle );
      jnif_release_env(mod->global);
      delete mod;
      mod = NULL;
    }
  }

  // when nif_init is done, we may need to "commit" data that
  // was made available to the NIF as char* data.
  jnif_commit_env(mod->global);

  // mod->global should be released when unloading
  return reinterpret_cast<jlong>(mod);
}

/*
 * Class:     erjang_NIF
 * Method:    jni_module_name
 * Signature: (J)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_erjang_NIF_jni_1module_1name
  (JNIEnv * je, jclass self, jlong mod_ptr)
{
    struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_ptr);

    return je->NewStringUTF(mod->entry->name);
}

/*
 * Class:     erjang_NIF
 * Method:    jni_fun_count
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_erjang_NIF_jni_1fun_1count
  (JNIEnv * je, jclass self, jlong mod_ptr)
{
    struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_ptr);

    return mod->entry->num_of_funcs;
}

/*
 * Class:     erjang_NIF
 * Method:    jni_fun_name
 * Signature: (JI)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_erjang_NIF_jni_1fun_1name
  (JNIEnv *je, jclass self, jlong mod_ptr, jint idx)
{
    struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_ptr);

    return je->NewStringUTF(mod->entry->funcs[idx].name);
}

/*
 * Class:     erjang_NIF
 * Method:    jni_fun_arity
 * Signature: (JI)I
 */
JNIEXPORT jint JNICALL Java_erjang_NIF_jni_1fun_1arity
  (JNIEnv *je, jclass self, jlong mod_ptr, jint idx)
{
    struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_ptr);

    return mod->entry->funcs[idx].arity;
}

JNIEXPORT jobject JNICALL Java_erjang_NIF_jni_1invoke
   (JNIEnv* je,
    jobject self,
    jobject proc,
    jlong mod_addr,
    jint index,
    jobjectArray args)
{
  struct jnif_module *mod =
    reinterpret_cast<struct jnif_module *>(mod_addr);

  ErlNifEntry *entry = mod->entry;
  if (index < 0 || index >= entry->num_of_funcs) {
    return NULL;
  }

  ErlNifFunc *func = &entry->funcs[index];
  jint size = je->GetArrayLength(args);

  ERL_NIF_TERM nif_args[size];
  for (int i = 0; i < size; i++) {
    jobject term = je->GetObjectArrayElement(args, i);
    nif_args[i] = (ERL_NIF_TERM)term;
  }

  struct enif_environment_t ee;
  jnif_init_env ( &ee, je, mod, enif_environment_t::STACK );
  ee.self = proc;

  ERL_NIF_TERM result = (*func->fptr)(&ee, size, nif_args);

  jnif_release_env( &ee );

  if (result == THE_BADARG) {
    je->CallStaticObjectMethod( ERT_class, m_ERT__badarg);
    return NULL;
  }

  return (jobject)result;
}

////////////

static void init_jvm_data(JavaVM *vm, JNIEnv* je)
{
  jvm = vm;

  jclass eobject_class      = je->FindClass("erjang/EObject");
  m_eobject__testReference  = je->GetMethodID(eobject_class, "testReference", "()Lerjang/ERef;");

  ERT_class = je->FindClass("erjang/ERT");
  ERT_class = (jclass)je->NewGlobalRef(ERT_class);
  m_ERT__badarg  = je->GetStaticMethodID(ERT_class, "badarg", "()Lerjang/ErlangError;");
}

extern "C" jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
  JNIEnv *je;
  if (vm->AttachCurrentThreadAsDaemon((void**)&je, NULL) == JNI_OK) {
    init_jvm_data(vm, je);
    initialize_jnif_env(vm,je);
    initialize_jnif_binary(vm,je);
    initialize_jnif_resource(vm,je);
    initialize_jnif_string(vm,je);
    initialize_jnif_number(vm,je);
    initialize_jnif_atom(vm,je);
    initialize_jnif_tuple(vm,je);
    initialize_jnif_list(vm, je);
    initialize_jnif_sys(vm, je);
    initialize_jnif_process(vm, je);
  }
  return JNI_VERSION_1_4;
}

extern "C" void JNI_OnUnload(JavaVM *vm, void *reserved)
{
  if (vm == jvm) {
    JNIEnv *je;
    if (vm->AttachCurrentThreadAsDaemon((void**)&je, NULL) == JNI_OK) {
      uninitialize_jnif_binary(vm, je);
    }
    jvm = NULL;
  }
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * c7a/net/net_manager.hpp
 *
 * Part of Project c7a.
 *
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_NET_NET_MANAGER_HEADER
#define C7A_NET_NET_MANAGER_HEADER

#include <c7a/net/net_endpoint.hpp>
#include <c7a/net/net_connection.hpp>
#include <c7a/net/net_dispatcher.hpp>
#include <c7a/net/net_group.hpp>

#include <vector>
#include <functional>

namespace c7a {
namespace net {

/**
 * @brief Manages communication.
 * @details Manages communication and handles errors.
 */
class NetManager
{
    static const bool debug = false;

public:
    static const size_t kGroupCount = 3;

private:
    NetGroup netGroups_[kGroupCount];
    lowlevel::Socket listenSocket_;
    NetConnection listenConnection_;
    size_t my_rank_;
    NetDispatcher dispatcher;
    std::vector<NetConnection> connections_;

    /**
     * @brief Converts a c7a endpoint list into a list of socket address.
     *
     * @param endpoints The endpoint list to convert.
     * @return The socket addresses to use internally.
     */
    std::vector<lowlevel::SocketAddress> GetAddressList(const std::vector<NetEndpoint>& endpoints) {
        std::vector<lowlevel::SocketAddress> addressList;

        for (const NetEndpoint& ne : endpoints)
        {
            addressList.push_back(lowlevel::SocketAddress(ne.hostport));
            if (!addressList.back().IsValid()) {
                throw Exception(
                          "Error resolving NetEndpoint " + ne.hostport
                          + ": " + addressList.back().GetResolveError());
            }
        }

        return addressList;
    }

    struct WelcomeMsg
    {
        uint32_t c7a;
        uint32_t groupId;
        ClientId id;
    };
    static const uint32_t c7a_sign = 0x0C7A0C7A;

    bool InitializationFinished(size_t endpointCount) {
        if (connections_.size() != (endpointCount - 1) * kGroupCount)
            return false;

        for (size_t i = 0; i < connections_.size(); i++)
            if (connections_[i].GetState() != ConnectionState::Connected)
                return false;

        return true;
    }

public:
    /**
     * @brief Spawns theads for each NetGroup and calls the given thread
     * function for each client to simulate.
     */
    static void ExecuteLocalMock(
        size_t num_clients,
        const std::function<void(NetGroup*)>& systemThreadFunction,
        const std::function<void(NetGroup*)>& flowThreadFunction,
        const std::function<void(NetGroup*)>& dataThreadFunction) {
        die_unless(kGroupCount == 3); //Adjust this method too if groupcount is different
        std::vector<std::thread*> threads(kGroupCount);

        threads[0] = new std::thread([=] {
                                         NetGroup::ExecuteLocalMock(num_clients, systemThreadFunction);
                                     });
        threads[1] = new std::thread([=] {
                                         NetGroup::ExecuteLocalMock(num_clients, flowThreadFunction);
                                     });
        threads[2] = new std::thread([=] {
                                         NetGroup::ExecuteLocalMock(num_clients, dataThreadFunction);
                                     });

        for (size_t i = 0; i != threads.size(); ++i) {
            threads[i]->join();
            delete threads[i];
        }
    }

    void Initialize(size_t my_rank_, const std::vector<NetEndpoint>& endpoints) {
        this->my_rank_ = my_rank_;

        if (connections_.size() != 0) {
            throw new Exception("This net manager has already been initialized.");
        }

        connections_.reserve(endpoints.size() * kGroupCount);

        for (size_t i = 0; i < kGroupCount; i++) {
            netGroups_[i].Initialize(my_rank_, endpoints.size());
        }

        die_unless(my_rank_ < endpoints.size());

        std::vector<lowlevel::SocketAddress> addressList = GetAddressList(endpoints);

        listenSocket_ = lowlevel::Socket::Create();
        listenSocket_.SetReuseAddr();

        const lowlevel::SocketAddress& lsa = addressList[my_rank_];

        if (listenSocket_.bind(lsa) != 0)
            throw Exception("Could not bind listen socket to "
                            + lsa.ToStringHostPort(), errno);

        if (listenSocket_.listen() != 0)
            throw Exception("Could not listen on socket "
                            + lsa.ToStringHostPort(), errno);

        listenConnection_ = std::move(NetConnection(listenSocket_));

        //TODO ej - remove when Connect(...) gets really async.
        sleep(1);

        // initiate connections to all hosts with higher id.

        for (ClientId id = my_rank_ + 1; id < addressList.size(); ++id)
        {
            for (uint32_t group = 0; group < kGroupCount; group++) {
                CreateAndConnect(id, addressList[id], group);
            }
        }

        dispatcher.AddRead(listenConnection_, [=](NetConnection& nc) {
                               return ConnectionReceived(nc);
                           });

        while (!InitializationFinished(endpoints.size()))
        {
            LOG << "Client " << my_rank_ << " dispatching.";
            dispatcher.Dispatch();
        }

        for (size_t i = 0; i < connections_.size(); i++) {
            size_t groupId = connections_[i].GetGroupId();
            die_unless(groupId < kGroupCount);
            netGroups_[groupId].AssignConnection(connections_[i]);
        }

        //Could dispose listen connection here.
        listenConnection_.Close();

        LOG << "Client " << my_rank_ << " done";

        for (uint32_t j = 0; j < kGroupCount; j++) {
            // output list of file descriptors connected to partners
            for (size_t i = 0; i != addressList.size(); ++i) {
                if (i == my_rank_) continue;
                LOG << "NetGroup " << j << " link " << my_rank_ << " -> " << i << " = fd "
                    << netGroups_[j].Connection(i).GetSocket().fd();
            }
        }
    }

    void CreateAndConnect(size_t id, lowlevel::SocketAddress& address, size_t group) {
        lowlevel::Socket ns = lowlevel::Socket::Create();
        connections_.emplace_back(ns, group, id);
        connections_.back().SetState(ConnectionState::Disconnected);

        Connect(connections_.back(), address);
    }

    void Connect(NetConnection& connection, lowlevel::SocketAddress& address) {
        die_unless(connection.GetSocket().IsValid());
        die_unless(connection.GetState() == ConnectionState::Disconnected);

        //TOOD ej - Make this really async.
        int res = connection.GetSocket().connect(address);

        connection.SetState(ConnectionState::Connecting);

        if (res == 0) {
            LOG << "Early connect  success. This should not happen.";
            // connect() already successful? this should not be.
            Connected(connection, address);
        }
        else if (errno == EINPROGRESS) {
            // connect is in progress, will wait for completion.
            dispatcher.AddRead(connection, [=](NetConnection& nc) {
                                   return Connected(nc, address);
                               });
        }
        else {
            //Failed to even try the connection - this might be a permanent error.
            connection.SetState(ConnectionState::Invalid);

            throw Exception("Could not connect to client "
                            + std::to_string(connection.GetPeerId()) + " via "
                            + address.ToStringHostPort(), errno);
        }
    }

    void HelloSent(NetConnection& conn) {
        if (conn.GetState() == ConnectionState::TransportConnected) {
            conn.SetState(ConnectionState::HelloSent);
        }
        else if (conn.GetState() == ConnectionState::HelloReceived) {
            conn.SetState(ConnectionState::Connected);
        }
        else {
            die("State mismatch");
        }
    }

    /**
     * @brief Called when a connection initiated by us succeeds.
     * @details
     * @return
     */
    bool Connected(NetConnection& conn, lowlevel::SocketAddress address) {
        int err = conn.GetSocket().GetError();

        if (err != 0) {
            conn.SetState(ConnectionState::Disconnected);
            //Try a reconnect
            //TODO(ej): Figure out if we need a timer here.
            Connect(conn, address);
        }

        die_unless(conn.GetSocket().IsValid());

        conn.SetState(ConnectionState::TransportConnected);

        LOG << "OpenConnections() " << my_rank_ << " connected"
            << " fd=" << conn.GetSocket().fd()
            << " to=" << conn.GetSocket().GetPeerAddress();

        // send welcome message
        const WelcomeMsg hello = { c7a_sign, (uint32_t)conn.GetGroupId(), (uint32_t)my_rank_ };

        dispatcher.AsyncWriteCopy(conn, &hello, sizeof(hello), [=](NetConnection& nc) {
                                      return HelloSent(nc);
                                  });

        LOG << "Client " << my_rank_ << " sent active hello to client ?";

        dispatcher.AsyncRead(conn, sizeof(hello),
                             [&](NetConnection& nc, Buffer&& b) {
                                 ReceiveWelcomeMessage(nc, std::move(b));
                             });

        return false;
    }

    /**
     * @brief Receives and handels a hello message.
     * @details
     *
     * @return
     */
    bool ReceiveWelcomeMessage(NetConnection& conn, Buffer&& buffer) {
        die_unless(conn.GetSocket().IsValid());
        die_unequal(buffer.size(), sizeof(WelcomeMsg));
        die_unequal(conn.GetState(), ConnectionState::HelloSent);

        const WelcomeMsg* msg = reinterpret_cast<const WelcomeMsg*>(buffer.data());
        die_unequal(msg->c7a, c7a_sign);
        //We already know those values since we connected actively.
        //So, check for any errors.
        die_unequal(conn.GetPeerId(), msg->id);
        die_unequal(conn.GetGroupId(), msg->groupId);

        conn.SetState(ConnectionState::Connected);

        LOG << "client " << my_rank_ << " got signature "
            << "from client " << msg->id;

        return false;
    }

    /**
     * @brief Receives and handels a hello message.
     * @details
     *
     * @return
     */
    bool ReceiveWelcomeMessageAndReply(NetConnection& conn, Buffer&& buffer) {
        die_unless(conn.GetSocket().IsValid());
        die_unless(conn.GetState() != ConnectionState::TransportConnected);

        const WelcomeMsg* msg = reinterpret_cast<const WelcomeMsg*>(buffer.data());
        die_unequal(msg->c7a, c7a_sign);
        LOG << "client " << my_rank_ << " got signature "
            << "from client " << msg->id;

        conn.SetState(ConnectionState::HelloReceived);

        const WelcomeMsg hello = { c7a_sign, msg->groupId, (ClientId)my_rank_ };

        // send welcome message

        conn.SetPeerId(msg->id);
        conn.SetGroupId(msg->groupId);
        dispatcher.AsyncWriteCopy(conn, &hello, sizeof(hello), [=](NetConnection& nc) {
                                      return HelloSent(nc);
                                  });

        LOG << "Client " << my_rank_ << " sent passive hello to client " << msg->id;

        return false;
    }

    bool ConnectionReceived(NetConnection& conn) {
        connections_.emplace_back(conn.GetSocket().accept());
        die_unless(connections_.back().GetSocket().IsValid());

        conn.SetState(ConnectionState::TransportConnected);

        LOG << "OpenConnections() " << my_rank_ << " accepted connection"
            << " fd=" << connections_.back().GetSocket().fd()
            << " from=" << connections_.back().GetPeerAddress();

        // wait for welcome message from other side
        dispatcher.AsyncRead(connections_.back(), sizeof(WelcomeMsg),
                             [&](NetConnection& nc, Buffer&& b) {
                                 ReceiveWelcomeMessageAndReply(nc, std::move(b));
                             });

        // wait for more connections?
        return true;
    }

    NetGroup & GetSystemNetGroup() {
        return netGroups_[0];
    }

    NetGroup & GetFlowNetGroup() {
        return netGroups_[1];
    }

    NetGroup & GetDataNetGroup() {
        return netGroups_[2];
    }
};

} // namespace net
} // namespace c7a

#endif // !C7A_NET_NET_MANAGER_HEADER

/******************************************************************************/
<commit_msg>Fixing NetManager variable naming style.<commit_after>/*******************************************************************************
 * c7a/net/net_manager.hpp
 *
 * Part of Project c7a.
 *
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_NET_NET_MANAGER_HEADER
#define C7A_NET_NET_MANAGER_HEADER

#include <c7a/net/net_endpoint.hpp>
#include <c7a/net/net_connection.hpp>
#include <c7a/net/net_dispatcher.hpp>
#include <c7a/net/net_group.hpp>

#include <vector>
#include <functional>

namespace c7a {
namespace net {

/**
 * @brief Manages communication.
 * @details Manages communication and handles errors.
 */
class NetManager
{
    static const bool debug = false;

public:
    static const size_t kGroupCount = 3;

private:
    NetGroup net_groups_[kGroupCount];
    NetConnection listener_;
    size_t my_rank_;
    NetDispatcher dispatcher_;
    std::vector<NetConnection> connections_;

    /**
     * @brief Converts a c7a endpoint list into a list of socket address.
     *
     * @param endpoints The endpoint list to convert.
     * @return The socket addresses to use internally.
     */
    std::vector<lowlevel::SocketAddress> GetAddressList(
        const std::vector<NetEndpoint>& endpoints) {
        std::vector<lowlevel::SocketAddress> addressList;

        for (const NetEndpoint& ne : endpoints)
        {
            addressList.push_back(lowlevel::SocketAddress(ne.hostport));
            if (!addressList.back().IsValid()) {
                throw Exception(
                          "Error resolving NetEndpoint " + ne.hostport
                          + ": " + addressList.back().GetResolveError());
            }
        }

        return addressList;
    }

    struct WelcomeMsg
    {
        uint32_t c7a;
        uint32_t groupId;
        ClientId id;
    };

    static const uint32_t c7a_sign = 0x0C7A0C7A;

    bool InitializationFinished(size_t endpointCount) {
        if (connections_.size() != (endpointCount - 1) * kGroupCount)
            return false;

        for (size_t i = 0; i < connections_.size(); i++)
            if (connections_[i].GetState() != ConnectionState::Connected)
                return false;

        return true;
    }

public:
    /**
     * @brief Spawns theads for each NetGroup and calls the given thread
     * function for each client to simulate.
     */
    static void ExecuteLocalMock(
        size_t num_clients,
        const std::function<void(NetGroup*)>& systemThreadFunction,
        const std::function<void(NetGroup*)>& flowThreadFunction,
        const std::function<void(NetGroup*)>& dataThreadFunction) {
        // Adjust this method too if groupcount is different
        die_unless(kGroupCount == 3);

        std::vector<std::thread*> threads(kGroupCount);

        threads[0] = new std::thread(
            [=] {
                NetGroup::ExecuteLocalMock(num_clients, systemThreadFunction);
            });
        threads[1] = new std::thread(
            [=] {
                NetGroup::ExecuteLocalMock(num_clients, flowThreadFunction);
            });
        threads[2] = new std::thread(
            [=] {
                NetGroup::ExecuteLocalMock(num_clients, dataThreadFunction);
            });

        for (size_t i = 0; i != threads.size(); ++i) {
            threads[i]->join();
            delete threads[i];
        }
    }

    void Initialize(size_t my_rank_, const std::vector<NetEndpoint>& endpoints) {
        this->my_rank_ = my_rank_;

        if (connections_.size() != 0) {
            throw new Exception("This net manager has already been initialized.");
        }

        connections_.reserve(endpoints.size() * kGroupCount);

        for (size_t i = 0; i < kGroupCount; i++) {
            net_groups_[i].Initialize(my_rank_, endpoints.size());
        }

        die_unless(my_rank_ < endpoints.size());

        std::vector<lowlevel::SocketAddress> addressList = GetAddressList(endpoints);

        {
            lowlevel::Socket listen_socket_ = lowlevel::Socket::Create();
            listen_socket_.SetReuseAddr();

            const lowlevel::SocketAddress& lsa = addressList[my_rank_];

            if (listen_socket_.bind(lsa) != 0)
                throw Exception("Could not bind listen socket to "
                                + lsa.ToStringHostPort(), errno);

            if (listen_socket_.listen() != 0)
                throw Exception("Could not listen on socket "
                                + lsa.ToStringHostPort(), errno);

            listener_ = std::move(NetConnection(listen_socket_));
        }

        //TODO ej - remove when Connect(...) gets really async.
        sleep(1);

        // initiate connections to all hosts with higher id.

        for (ClientId id = my_rank_ + 1; id < addressList.size(); ++id)
        {
            for (uint32_t group = 0; group < kGroupCount; group++) {
                CreateAndConnect(id, addressList[id], group);
            }
        }

        dispatcher_.AddRead(listener_,
                            [=](NetConnection& nc) {
                                return ConnectionReceived(nc);
                            });

        while (!InitializationFinished(endpoints.size()))
        {
            LOG << "Client " << my_rank_ << " dispatching.";
            dispatcher_.Dispatch();
        }

        for (size_t i = 0; i < connections_.size(); i++) {
            size_t groupId = connections_[i].GetGroupId();
            die_unless(groupId < kGroupCount);
            net_groups_[groupId].AssignConnection(connections_[i]);
        }

        //Could dispose listen connection here.
        listener_.Close();

        LOG << "Client " << my_rank_ << " done";

        for (uint32_t j = 0; j < kGroupCount; j++) {
            // output list of file descriptors connected to partners
            for (size_t i = 0; i != addressList.size(); ++i) {
                if (i == my_rank_) continue;
                LOG << "NetGroup " << j << " link " << my_rank_ << " -> " << i << " = fd "
                    << net_groups_[j].Connection(i).GetSocket().fd();
            }
        }
    }

    void CreateAndConnect(
        size_t id, lowlevel::SocketAddress& address, size_t group) {
        lowlevel::Socket ns = lowlevel::Socket::Create();
        connections_.emplace_back(ns, group, id);
        connections_.back().SetState(ConnectionState::Disconnected);

        Connect(connections_.back(), address);
    }

    void Connect(NetConnection& connection, lowlevel::SocketAddress& address) {
        die_unless(connection.GetSocket().IsValid());
        die_unless(connection.GetState() == ConnectionState::Disconnected);

        //TOOD ej - Make this really async.
        int res = connection.GetSocket().connect(address);

        connection.SetState(ConnectionState::Connecting);

        if (res == 0) {
            LOG << "Early connect  success. This should not happen.";
            // connect() already successful? this should not be.
            Connected(connection, address);
        }
        else if (errno == EINPROGRESS) {
            // connect is in progress, will wait for completion.
            dispatcher_.AddRead(connection, [=](NetConnection& nc) {
                                    return Connected(nc, address);
                                });
        }
        else {
            //Failed to even try the connection - this might be a permanent error.
            connection.SetState(ConnectionState::Invalid);

            throw Exception("Could not connect to client "
                            + std::to_string(connection.GetPeerId()) + " via "
                            + address.ToStringHostPort(), errno);
        }
    }

    void HelloSent(NetConnection& conn) {
        if (conn.GetState() == ConnectionState::TransportConnected) {
            conn.SetState(ConnectionState::HelloSent);
        }
        else if (conn.GetState() == ConnectionState::HelloReceived) {
            conn.SetState(ConnectionState::Connected);
        }
        else {
            die("State mismatch");
        }
    }

    /**
     * @brief Called when a connection initiated by us succeeds.
     * @details
     * @return
     */
    bool Connected(NetConnection& conn, lowlevel::SocketAddress address) {
        int err = conn.GetSocket().GetError();

        if (err != 0) {
            conn.SetState(ConnectionState::Disconnected);
            //Try a reconnect
            //TODO(ej): Figure out if we need a timer here.
            Connect(conn, address);
        }

        die_unless(conn.GetSocket().IsValid());

        conn.SetState(ConnectionState::TransportConnected);

        LOG << "OpenConnections() " << my_rank_ << " connected"
            << " fd=" << conn.GetSocket().fd()
            << " to=" << conn.GetSocket().GetPeerAddress();

        // send welcome message
        const WelcomeMsg hello = {
            c7a_sign, (uint32_t)conn.GetGroupId(), (uint32_t)my_rank_
        };

        dispatcher_.AsyncWriteCopy(conn, &hello, sizeof(hello),
                                   [=](NetConnection& nc) {
                                       return HelloSent(nc);
                                   });

        LOG << "Client " << my_rank_ << " sent active hello to client ?";

        dispatcher_.AsyncRead(conn, sizeof(hello),
                              [&](NetConnection& nc, Buffer&& b) {
                                  ReceiveWelcomeMessage(nc, std::move(b));
                              });

        return false;
    }

    /**
     * @brief Receives and handels a hello message.
     * @details
     *
     * @return
     */
    bool ReceiveWelcomeMessage(NetConnection& conn, Buffer&& buffer) {
        die_unless(conn.GetSocket().IsValid());
        die_unequal(buffer.size(), sizeof(WelcomeMsg));
        die_unequal(conn.GetState(), ConnectionState::HelloSent);

        const WelcomeMsg* msg = reinterpret_cast<const WelcomeMsg*>(buffer.data());
        die_unequal(msg->c7a, c7a_sign);
        //We already know those values since we connected actively.
        //So, check for any errors.
        die_unequal(conn.GetPeerId(), msg->id);
        die_unequal(conn.GetGroupId(), msg->groupId);

        conn.SetState(ConnectionState::Connected);

        LOG << "client " << my_rank_ << " got signature "
            << "from client " << msg->id;

        return false;
    }

    /**
     * @brief Receives and handels a hello message.
     * @details
     *
     * @return
     */
    bool ReceiveWelcomeMessageAndReply(NetConnection& conn, Buffer&& buffer) {
        die_unless(conn.GetSocket().IsValid());
        die_unless(conn.GetState() != ConnectionState::TransportConnected);

        const WelcomeMsg* msg = reinterpret_cast<const WelcomeMsg*>(buffer.data());
        die_unequal(msg->c7a, c7a_sign);
        LOG << "client " << my_rank_ << " got signature "
            << "from client " << msg->id;

        conn.SetState(ConnectionState::HelloReceived);

        const WelcomeMsg hello = { c7a_sign, msg->groupId, (ClientId)my_rank_ };

        // send welcome message

        conn.SetPeerId(msg->id);
        conn.SetGroupId(msg->groupId);

        dispatcher_.AsyncWriteCopy(conn, &hello, sizeof(hello),
                                   [=](NetConnection& nc) {
                                       return HelloSent(nc);
                                   });

        LOG << "Client " << my_rank_ << " sent passive hello to client " << msg->id;

        return false;
    }

    bool ConnectionReceived(NetConnection& conn) {
        connections_.emplace_back(conn.GetSocket().accept());
        die_unless(connections_.back().GetSocket().IsValid());

        conn.SetState(ConnectionState::TransportConnected);

        LOG << "OpenConnections() " << my_rank_ << " accepted connection"
            << " fd=" << connections_.back().GetSocket().fd()
            << " from=" << connections_.back().GetPeerAddress();

        // wait for welcome message from other side
        dispatcher_.AsyncRead(connections_.back(), sizeof(WelcomeMsg),
                              [&](NetConnection& nc, Buffer&& b) {
                                  ReceiveWelcomeMessageAndReply(nc, std::move(b));
                              });

        // wait for more connections?
        return true;
    }

    NetGroup & GetSystemNetGroup() {
        return net_groups_[0];
    }

    NetGroup & GetFlowNetGroup() {
        return net_groups_[1];
    }

    NetGroup & GetDataNetGroup() {
        return net_groups_[2];
    }
};

} // namespace net
} // namespace c7a

#endif // !C7A_NET_NET_MANAGER_HEADER

/******************************************************************************/
<|endoftext|>