virtual void HandleMessage(const Var& var_message) { if (busy) return; busy = true; static int thread_pool_size = 8; static int halide_last_t = 0; static int halide_time_weight = 0; static int last_demo = -1; int demo = 0; if (var_message.is_string()) { std::string msg = var_message.AsString(); int threads = atoi(msg.c_str()+2); if (threads < 1) threads = 1; if (threads > 32) threads = 32; if (threads > 0 && threads <= 32 && thread_pool_size != threads) { halide_shutdown_thread_pool(); thread_pool_size = threads; char buf[256]; snprintf(buf, 256, "%d", threads); setenv("HL_NUMTHREADS", buf, 1); halide_last_t = 0; halide_time_weight = 0; } demo = msg[0] - '0'; } static bool first_run = true; if (first_run) { first_run = false; setenv("HL_NUMTHREADS", "8", 1); } // Initialize the input if (demo != last_demo) { last_demo = demo; // Delete any existing state free_buffer(&state_1); free_buffer(&state_2); halide_last_t = 0; halide_time_weight = 0; switch (demo) { case 0: // Query how large the state arrays need to be in // order to hit our render target using Halide's // bounds query mode. game_of_life_render(&state_1, &render_target); state_2 = state_1; alloc_buffer(&state_1); alloc_buffer(&state_2); // Initialize into the first one game_of_life_init(&state_1); break; case 1: julia_render(&state_1, &render_target); state_2 = state_1; alloc_buffer(&state_1); alloc_buffer(&state_2); julia_init(&state_1); break; case 2: reaction_diffusion_render(&state_1, &render_target); state_2 = state_1; alloc_buffer(&state_1); alloc_buffer(&state_2); print_buffer(&state_1); reaction_diffusion_init(&state_1); break; case 3: reaction_diffusion_2_render(&state_1, &render_target); state_2 = state_1; alloc_buffer(&state_1); alloc_buffer(&state_2); print_buffer(&state_1); reaction_diffusion_2_init(&state_1); break; default: PostMessage("Bad demo index"); return; } } if (pipeline_barfed) { return; } timeval t1, t2; gettimeofday(&t1, NULL); switch (demo) { case 0: game_of_life_update(&state_1, mouse_x, mouse_y, &state_2); game_of_life_render(&state_2, &render_target); break; case 1: julia_update(&state_1, mouse_x, mouse_y, &state_2); julia_render(&state_2, &render_target); break; case 2: reaction_diffusion_update(&state_1, mouse_x, mouse_y, &state_2); reaction_diffusion_render(&state_2, &render_target); break; case 3: reaction_diffusion_2_update(&state_1, mouse_x, mouse_y, &state_2); reaction_diffusion_2_render(&state_2, &render_target); break; } gettimeofday(&t2, NULL); std::swap(state_1, state_2); mouse_x = mouse_y = -100; if (pipeline_barfed) { return; } int t = t2.tv_usec - t1.tv_usec; t += (t2.tv_sec - t1.tv_sec)*1000000; // Smooth it out so we can see a rolling average t = (halide_last_t * halide_time_weight + t) / (halide_time_weight + 1); halide_last_t = t; if (halide_time_weight < 100) { halide_time_weight++; } std::ostringstream oss; oss << "<table cellspacing=8><tr><td width=200 height=30>Halide routine takes:</td><td>"; if (halide_time_weight < 10) { oss << "?"; } else { oss << halide_last_t; } oss << " us</td></tr></table>"; PostMessage(oss.str()); graphics.PaintImageData(framebuffer, Point(0, 0)); graphics.Flush(callback); }
/// Handler for messages coming in from the browser via postMessage(). The /// @a var_message can contain anything: a JSON string; a string that encodes /// method names and arguments; etc. For example, you could use /// JSON.stringify in the browser to create a message that contains a method /// name and some parameters, something like this: /// var json_message = JSON.stringify({ "myMethod" : "3.14159" }); /// nacl_module.postMessage(json_message); /// On receipt of this message in @a var_message, you could parse the JSON to /// retrieve the method name, match it to a function call, and then call it /// with the parameter. /// @param[in] var_message The message posted by the browser. virtual void HandleMessage(const Var& var_message) { if (busy) return; busy = true; static int thread_pool_size = 8; static int halide_last_t = 0; static int halide_time_weight = 0; static int c_last_t = 0; static int c_time_weight = 0; static bool use_halide = true; if (var_message.is_string()) { std::string msg = var_message.AsString(); int threads = atoi(msg.c_str()+2); if (threads < 1) threads = 1; if (threads > 32) threads = 32; if (threads > 0 && threads <= 32 && thread_pool_size != threads) { halide_shutdown_thread_pool(); thread_pool_size = threads; char buf[256]; snprintf(buf, 256, "%d", threads); setenv("HL_NUMTHREADS", buf, 1); halide_last_t = 0; halide_time_weight = 0; } bool new_use_halide = (msg[0] == '0'); if (new_use_halide != use_halide) { use_halide = new_use_halide; } } buffer_t input = ImageToBuffer(im1); buffer_t output = ImageToBuffer(im2); // Only compute the inner part of output so that we don't have // to worry about boundary conditions. output.min[0] = output.min[1] = MARGIN; output.extent[0] -= MARGIN*2; output.extent[1] -= MARGIN*2; output.host += (output.stride[1] + output.stride[0]) * MARGIN * 4; // Initialize the input with noise static bool first_run = true; if (first_run) { first_run = false; // Start with 8 threads setenv("HL_NUMTHREADS", "8", 1); // Initialize the buffers memset(im2.data(), 0, im2.stride() * im2.size().height()); for (int y = 0; y < HEIGHT; y++) { uint8_t *ptr = ((uint8_t *)im1.data()) + im1.stride() * y; for (int x = 0; x < WIDTH; x++) { ptr[x*4] = ((rand() & 31) == 0) ? 255 : 0; ptr[x*4+1] = ((rand() & 31) == 0) ? 255 : 0; ptr[x*4+2] = ((rand() & 31) == 0) ? 255 : 0; ptr[x*4+3] = (x >= MARGIN && (x < (WIDTH - MARGIN)) && y >= MARGIN && y < (HEIGHT - MARGIN)) ? 255 : 0; } } } timeval t1, t2; gettimeofday(&t1, NULL); if (use_halide) { halide_game_of_life(&input, &output); } else { c_game_of_life(&input, &output); } gettimeofday(&t2, NULL); if (pipeline_barfed) return; int t = t2.tv_usec - t1.tv_usec; t += (t2.tv_sec - t1.tv_sec)*1000000; // Smooth it out so we can see a rolling average if (use_halide) { t = (halide_last_t * halide_time_weight + t) / (halide_time_weight + 1); halide_last_t = t; if (halide_time_weight < 100) { halide_time_weight++; } } else { t = (c_last_t * c_time_weight + t) / (c_time_weight + 1); c_last_t = t; if (c_time_weight < 100) { c_time_weight++; } } std::ostringstream oss; oss << "<table cellspacing=8><tr><td width=200 height=30>Halide routine takes:</td><td>"; if (halide_time_weight < 10) { oss << "?"; } else { if (use_halide) oss << "<b>"; oss << halide_last_t; if (use_halide) oss << "</b>"; } oss << " us</td></tr><tr><td width=200 height=30>Scalar C routine takes:</td><td>"; if (c_time_weight < 10) { oss << "?"; } else { if (!use_halide) oss << "<b>"; oss << c_last_t; if (!use_halide) oss << "</b>"; } oss << " us</td></tr></table>"; PostMessage(oss.str()); graphics.PaintImageData(im2, Point(0, 0)); graphics.Flush(callback); std::swap(im1, im2); }