1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <fcntl.h> 6 #include <stdio.h> 7 #include <string.h> 8 #include <sys/mman.h> 9 #include <sys/stat.h> 10 #include <unistd.h> 11 12 #include "base/logging.h" 13 14 #include "glinterface.h" 15 #include "main.h" 16 #include "utils.h" 17 18 using base::FilePath; 19 20 const char* kGlesHeader = 21 "#ifdef GL_ES\n" 22 "precision highp float;\n" 23 "#endif\n"; 24 25 FilePath *g_base_path = new FilePath(); 26 double g_initial_temperature = -1000.0; 27 28 // Sets the base path for MmapFile to `dirname($argv0)`/$relative. 29 void SetBasePathFromArgv0(const char* argv0, const char* relative) { 30 if (g_base_path) { 31 delete g_base_path; 32 } 33 FilePath argv0_path = FilePath(argv0).DirName(); 34 FilePath base_path = relative ? argv0_path.Append(relative) : argv0_path; 35 g_base_path = new FilePath(base_path); 36 } 37 38 const FilePath& GetBasePath() { 39 return *g_base_path; 40 } 41 42 void *MmapFile(const char* name, size_t* length) { 43 FilePath filename = g_base_path->Append(name); 44 int fd = open(filename.value().c_str(), O_RDONLY); 45 if (fd == -1) 46 return NULL; 47 48 struct stat sb; 49 CHECK(fstat(fd, &sb) != -1); 50 51 char *mmap_ptr = static_cast<char *>( 52 mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0)); 53 54 close(fd); 55 56 if (mmap_ptr) 57 *length = sb.st_size; 58 59 return mmap_ptr; 60 } 61 62 bool read_int_from_file(FilePath filename, int *value) { 63 FILE *fd = fopen(filename.value().c_str(), "r"); 64 if (!fd) { 65 return false; 66 } 67 int count = fscanf(fd, "%d", value); 68 if (count != 1) { 69 printf("Error: could not read integer from file. (%s)\n", 70 filename.value().c_str()); 71 if(count != 1) 72 return false; 73 } 74 fclose(fd); 75 return true; 76 } 77 78 // Returns temperature at which CPU gets throttled. 79 // TODO(ihf): update this based on the outcome of crbug.com/356422. 80 double get_temperature_critical() { 81 FilePath filename = FilePath("/sys/class/hwmon/hwmon0/temp1_crit"); 82 int temperature_mCelsius = 0; 83 if (!read_int_from_file(filename, &temperature_mCelsius)) { 84 // spring is special :-(. 85 filename = FilePath("/sys/devices/virtual/hwmon/hwmon1/temp1_crit"); 86 if (!read_int_from_file(filename, &temperature_mCelsius)) { 87 // 85'C is the minimum observed critical temperature so far. 88 printf("Warning: guessing critical temperature as 85'C.\n"); 89 return 85.0; 90 } 91 } 92 double temperature_Celsius = 0.001 * temperature_mCelsius; 93 // Simple sanity check for reasonable critical temperatures. 94 assert(temperature_Celsius >= 60.0); 95 assert(temperature_Celsius <= 150.0); 96 return temperature_Celsius; 97 } 98 99 100 // Returns currently measured temperature. 101 // TODO(ihf): update this based on the outcome of crbug.com/356422. 102 double get_temperature_input() { 103 FilePath filenames[] = { 104 FilePath("/sys/class/hwmon/hwmon0/temp1_input"), 105 FilePath("/sys/class/hwmon/hwmon1/temp1_input"), 106 FilePath("/sys/devices/platform/coretemp.0/temp1_input"), 107 FilePath("/sys/devices/platform/coretemp.0/temp2_input"), 108 FilePath("/sys/devices/platform/coretemp.0/temp3_input"), 109 FilePath("/sys/devices/virtual/hwmon/hwmon0/temp1_input"), 110 FilePath("/sys/devices/virtual/hwmon/hwmon0/temp2_input"), 111 FilePath("/sys/devices/virtual/hwmon/hwmon1/temp1_input"), 112 FilePath("/sys/devices/virtual/hwmon/hwmon2/temp1_input"), 113 FilePath("/sys/devices/virtual/hwmon/hwmon3/temp1_input"), 114 FilePath("/sys/devices/virtual/hwmon/hwmon4/temp1_input"), 115 }; 116 117 int temperature_mCelsius = 0; 118 int max_temperature_mCelsius = -1000000.0; 119 for (unsigned int i = 0; i < sizeof(filenames) / sizeof(FilePath); i++) { 120 if (read_int_from_file(filenames[i], &temperature_mCelsius)) { 121 // Hack: Ignore values outside of 10'C...150'C for now. 122 if (temperature_mCelsius < 10000 || temperature_mCelsius > 150000) { 123 printf("Warning: ignoring temperature reading of %d m'C.\n", 124 temperature_mCelsius); 125 } else { 126 max_temperature_mCelsius = std::max(max_temperature_mCelsius, 127 temperature_mCelsius); 128 } 129 } 130 } 131 132 double temperature_Celsius = 0.001 * max_temperature_mCelsius; 133 if (temperature_Celsius < 10.0 || temperature_Celsius > 150.0) { 134 printf("Warning: ignoring temperature reading of %f'C.\n", 135 temperature_Celsius); 136 } 137 138 return temperature_Celsius; 139 } 140 141 const double GetInitialMachineTemperature() { 142 return g_initial_temperature; 143 } 144 145 // TODO(ihf): update this based on the outcome of crbug.com/356422. 146 // In particular we should probably just have a system script that we can call 147 // and read the output from. 148 double GetMachineTemperature() { 149 double max_temperature = get_temperature_input(); 150 return max_temperature; 151 } 152 153 // Waits up to timeout seconds to reach cold_temperature in Celsius. 154 double WaitForCoolMachine(double cold_temperature, double timeout, 155 double *temperature) { 156 // Integer times are in micro-seconds. 157 uint64_t time_start = GetUTime(); 158 uint64_t time_now = time_start; 159 uint64_t time_end = time_now + 1e6 * timeout; 160 *temperature = GetMachineTemperature(); 161 while (time_now < time_end) { 162 if (*temperature < cold_temperature) 163 break; 164 sleep(1.0); 165 time_now = GetUTime(); 166 *temperature = GetMachineTemperature(); 167 } 168 double wait_time = 1.0e-6 * (time_now - time_start); 169 assert(wait_time >= 0); 170 assert(wait_time < timeout + 5.0); 171 return wait_time; 172 } 173 174 namespace glbench { 175 176 GLuint SetupTexture(GLsizei size_log2) { 177 GLsizei size = 1 << size_log2; 178 GLuint name = ~0; 179 glGenTextures(1, &name); 180 glBindTexture(GL_TEXTURE_2D, name); 181 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 182 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 183 184 unsigned char *pixels = new unsigned char[size * size * 4]; 185 if (!pixels) 186 return 0; 187 188 for (GLint level = 0; size > 0; level++, size /= 2) { 189 unsigned char *p = pixels; 190 for (int i = 0; i < size; i++) { 191 for (int j = 0; j < size; j++) { 192 *p++ = level %3 != 0 ? (i ^ j) << level : 0; 193 *p++ = level %3 != 1 ? (i ^ j) << level : 0; 194 *p++ = level %3 != 2 ? (i ^ j) << level : 0; 195 *p++ = 255; 196 } 197 } 198 if (size == 1) { 199 unsigned char *p = pixels; 200 *p++ = 255; 201 *p++ = 255; 202 *p++ = 255; 203 *p++ = 255; 204 } 205 glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, size, size, 0, 206 GL_RGBA, GL_UNSIGNED_BYTE, pixels); 207 } 208 delete[] pixels; 209 return name; 210 } 211 212 GLuint SetupVBO(GLenum target, GLsizeiptr size, const GLvoid *data) { 213 GLuint buf = ~0; 214 glGenBuffers(1, &buf); 215 glBindBuffer(target, buf); 216 glBufferData(target, size, data, GL_STATIC_DRAW); 217 CHECK(!glGetError()); 218 return buf; 219 } 220 221 // Generates a lattice symmetric around the origin (all quadrants). 222 void CreateLattice(GLfloat **vertices, GLsizeiptr *size, 223 GLfloat size_x, GLfloat size_y, int width, int height) 224 { 225 GLfloat *vptr = *vertices = new GLfloat[2 * (width + 1) * (height + 1)]; 226 GLfloat shift_x = size_x * width; 227 GLfloat shift_y = size_y * height; 228 for (int j = 0; j <= height; j++) { 229 for (int i = 0; i <= width; i++) { 230 *vptr++ = 2 * i * size_x - shift_x; 231 *vptr++ = 2 * j * size_y - shift_y; 232 } 233 } 234 *size = (vptr - *vertices) * sizeof(GLfloat); 235 } 236 237 // Generates a mesh of 2*width*height triangles. The ratio of front facing to 238 // back facing triangles is culled_ratio/RAND_MAX. Returns the number of 239 // vertices in the mesh. 240 int CreateMesh(GLushort **indices, GLsizeiptr *size, 241 int width, int height, int culled_ratio) { 242 srand(0); 243 244 // We use 16 bit indices for compatibility with GL ES 245 CHECK(height * width + width + height <= 65535); 246 247 GLushort *iptr = *indices = new GLushort[2 * 3 * (width * height)]; 248 const int swath_height = 4; 249 250 CHECK(width % swath_height == 0 && height % swath_height == 0); 251 252 for (int j = 0; j < height; j += swath_height) { 253 for (int i = 0; i < width; i++) { 254 for (int j2 = 0; j2 < swath_height; j2++) { 255 GLushort first = (j + j2) * (width + 1) + i; 256 GLushort second = first + 1; 257 GLushort third = first + (width + 1); 258 GLushort fourth = third + 1; 259 260 bool flag = rand() < culled_ratio; 261 *iptr++ = first; 262 *iptr++ = flag ? second : third; 263 *iptr++ = flag ? third : second; 264 265 *iptr++ = fourth; 266 *iptr++ = flag ? third : second; 267 *iptr++ = flag ? second : third; 268 } 269 } 270 } 271 *size = (iptr - *indices) * sizeof(GLushort); 272 273 return iptr - *indices; 274 } 275 276 static void print_info_log(int obj, bool shader) 277 { 278 char info_log[4096]; 279 int length; 280 281 if (shader) 282 glGetShaderInfoLog(obj, sizeof(info_log)-1, &length, info_log); 283 else 284 glGetProgramInfoLog(obj, sizeof(info_log)-1, &length, info_log); 285 286 char *p = info_log; 287 while (p < info_log + length) { 288 char *newline = strchr(p, '\n'); 289 if (newline) 290 *newline = '\0'; 291 printf("# Info: glGet%sInfoLog: %s\n", shader ? "Shader" : "Program", p); 292 if (!newline) 293 break; 294 p = newline + 1; 295 } 296 } 297 298 static void print_shader_log(int shader) 299 { 300 print_info_log(shader, true); 301 } 302 303 static void print_program_log(int program) 304 { 305 print_info_log(program, false); 306 } 307 308 309 GLuint InitShaderProgram(const char *vertex_src, const char *fragment_src) { 310 return InitShaderProgramWithHeader(NULL, vertex_src, fragment_src); 311 } 312 313 GLuint InitShaderProgramWithHeader(const char* header, 314 const char* vertex_src, 315 const char* fragment_src) { 316 const char* headers[] = {kGlesHeader, header}; 317 return InitShaderProgramWithHeaders(headers, 318 arraysize(headers) - (header ? 0 : 1), 319 vertex_src, fragment_src); 320 } 321 322 GLuint InitShaderProgramWithHeaders(const char** headers, 323 int count, 324 const char* vertex_src, 325 const char* fragment_src) { 326 GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); 327 GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); 328 329 const char** header_and_body = new const char*[count + 1]; 330 if (count != 0) 331 memcpy(header_and_body, headers, count * sizeof(const char*)); 332 header_and_body[count] = vertex_src; 333 glShaderSource(vertex_shader, count + 1, header_and_body, NULL); 334 header_and_body[count] = fragment_src; 335 glShaderSource(fragment_shader, count + 1, header_and_body, NULL); 336 delete[] header_and_body; 337 338 glCompileShader(vertex_shader); 339 print_shader_log(vertex_shader); 340 glCompileShader(fragment_shader); 341 print_shader_log(fragment_shader); 342 343 GLuint program = glCreateProgram(); 344 glAttachShader(program, vertex_shader); 345 glAttachShader(program, fragment_shader); 346 glLinkProgram(program); 347 print_program_log(program); 348 glUseProgram(program); 349 350 glDeleteShader(vertex_shader); 351 glDeleteShader(fragment_shader); 352 353 return program; 354 } 355 356 void ClearBuffers() { 357 glClearColor(1.f, 0, 0, 1.f); 358 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 359 g_main_gl_interface->SwapBuffers(); 360 glClearColor(0, 1.f, 0, 1.f); 361 glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); 362 g_main_gl_interface->SwapBuffers(); 363 glClearColor(0, 0, 0.f, 1.f); 364 } 365 366 } // namespace glbench 367