void launch_manual() { char command[512]; char *manual_file = find_manual_file(); if (!manual_file) { fprintf(stderr, "No manual found.\n"); return; } #ifdef __APPLE__ snprintf(command, sizeof(command), "%s/%s", get_data_dir(), manual_file); void open_file_with_browser_mac(char *file); open_file_with_browser_mac(command); #else switch (arch) { case ARCH_WETAB: snprintf(command, sizeof(command), "tiitoo-browser-bin -t file://%s/%s", get_data_dir(), manual_file); break; case ARCH_WIN32: case ARCH_WIN64: snprintf(command, sizeof(command), "%s", manual_file); break; default: if (!strcmp(options_browser, "browser")) { strcpy(options_browser, "./browser.sh"); } snprintf(command, sizeof(command), "%s file://%s/%s", options_browser, get_data_dir(), manual_file); break; } launch_command(command); #endif }
void show_history(char * historyfile) { char workstring[1024]; // build the browser call string #ifdef __APPLE__ sprintf(workstring,"%s/html/%s",file_name,historyfile); void open_file_with_browser_mac(char *file); open_file_with_browser_mac(workstring); #else #ifdef USE_WIN sprintf(workstring,"%s/html/%s",file_name,historyfile); #else char callstring[1024]; get_browser(callstring); sprintf(workstring," %s%s/html/%s",callstring,file_name,historyfile); #endif launch_command(workstring); #endif }
/* @desc Prints collected data to an output file, and manages benchmark execution. @input int pid -- child process id @errors print_data will terminate the program if: -the output file already exists -the output file is invalid or can't be opened */ void collect_data() { //##launch benchmark## int *pids = (int *)malloc(sizeof(int)*options_opt.num_processes); //0 = not exited. 1 = exited. int *pid_exited = (int *)malloc(sizeof(int)*options_opt.num_processes); int k; for(k = 0; k < options_opt.num_processes; k++) { int pid = launch_command(options_opt.cmd); pid_exited[k] = 0; pids[k] = pid; } completed_ms = 0; //open file descriptors int freq_fds[num_cores]; char freq_buf[70]; for(k = 0; k < num_cores; k++) { snprintf(freq_buf, sizeof(freq_buf), "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_cur_freq", k); freq_fds[k] = open(freq_buf, O_RDONLY); if(freq_fds[k] < 0) { die("Opening cpu frequency failed. %s\n", strerror(errno)); } } //controller control_info_t control_data; //##output data## const struct timespec delay = {INTERVAL/1000,(INTERVAL%1000)*10e6}; int sent_kill = 0; while(!done) { if(options_opt.timeout && completed_ms>timeout_ms && !sent_kill) { for(k = 0; k < options_opt.num_processes; k++) { kill_command(pids[k]); } /*The purpose of marking sent_kill is to avoid sending kill signals twice. It's possible that the signal is sent, but that the process does not terminate immediately. Therefore, the data collection loop may occur one or more time subsequently; in these situations we do not want to resend the kill signal or collect new data. Initially, I did not have this variable, and I actually encountered this bug.*/ sent_kill = 1; } done = 1; for(k = 0; k < options_opt.num_processes; k++) { if(!pid_exited[k]) if(waitpid(pids[k], 0, WNOHANG)) pid_exited[k] = 1; } for(k = 0; k < options_opt.num_processes; k++) { if(!pid_exited[k]) { done = 0; break; } } if(!sent_kill) { //temperatures int i; for(i = 0; i < num_cores; i++) { double t; int temp_status = temp_read(i, &t); if(temp_status != 0) { die("error %d: reading core %d T", temp_status, i); } fprintf(output_file_handle, "%-15.1f", t); control_data.ts[i] = t; } //power control_data.pcpu = 0; for(i = 0; i < NUM_PWR_CHANNELS; i++) { fprintf(output_file_handle, "%-15.8f ", curr_pwr[i]); control_data.pcpu += curr_pwr[i]*MV_TO_CPU_POWER; } //fan speeds double fspeed; for(i = 0; i < NUM_FANS; i++) { fan_read(i,&fspeed); fprintf(output_file_handle, "%-15.5f", fspeed); } //power supplies. If we are not collecting data from //the power supplies, the globals are initialized to zero //and we will read these values. control_data.ptec = 0; for(i = 0; i < NUM_PWS_CHANNELS; i++) { fprintf(output_file_handle, "%-15.5f", curr_pws_v[i]); fprintf(output_file_handle, "%-15.5f", curr_pws_i[i]); control_data.ptec += curr_pws_v[i]*curr_pws_i[i]; } //timestamp [ms] fprintf(output_file_handle, "%-15d", (int)completed_ms); //frequencies [khz] for(i = 0; i < num_cores; i++) { if(lseek(freq_fds[i],0,SEEK_SET) < 0) die("Seeking cpu freq. %s\n", strerror(errno)); int bytesread = read(freq_fds[i], freq_buf, sizeof(freq_buf)); if(bytesread < 0) { die("Reading cpu frequency failed. %s\n", strerror(errno)); } //-1 to remove newline. TODO robust newline stripping freq_buf[bytesread-1] = 0; fprintf(output_file_handle, "%-15.2f", atoi(freq_buf)/1000000.0); } fprintf(output_file_handle, "\n"); //control #ifdef CONTROL_ENABLE if(completed_ms % (options_opt.control_params.interval*INTERVAL) == 0) { control_simple(control_data); } #endif } //nanosleep can be interrupted by signals, but //this case doesn't need to be handled in any special way. //If the child terminates, done will be set and data //collection will finish. nanosleep(&delay, NULL); completed_ms += INTERVAL; } for(k = 0; k < num_cores; k++) { if(close(freq_fds[k]) < 0) die("Could not close cpu freq fds %s\n", strerror(errno)); } free(pids); free(pid_exited); }