Home | History | Annotate | Download | only in src
      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