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.
SetBasePathFromArgv0(const char * argv0,const char * 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 
GetBasePath()38 const FilePath& GetBasePath() {
39   return *g_base_path;
40 }
41 
MmapFile(const char * name,size_t * length)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 
read_int_from_file(FilePath filename,int * value)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.
get_temperature_critical()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.
get_temperature_input()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       // kevin & elm
116       FilePath("/sys/devices/virtual/thermal/thermal_zone0/temp"),
117       FilePath("/sys/devices/virtual/thermal/thermal_zone1/temp"),
118       FilePath("/sys/devices/virtual/thermal/thermal_zone2/temp"),
119       FilePath("/sys/devices/virtual/thermal/thermal_zone3/temp"),
120       FilePath("/sys/devices/virtual/thermal/thermal_zone4/temp"),
121   };
122 
123   int temperature_mCelsius = 0;
124   int max_temperature_mCelsius = -1000000.0;
125   for (unsigned int i = 0; i < sizeof(filenames) / sizeof(FilePath); i++) {
126     if (read_int_from_file(filenames[i], &temperature_mCelsius)) {
127       // Hack: Ignore values outside of 10'C...150'C for now.
128       if (temperature_mCelsius < 10000 || temperature_mCelsius > 150000) {
129         printf("Warning: ignoring temperature reading of %d m'C.\n",
130                temperature_mCelsius);
131       } else {
132         max_temperature_mCelsius = std::max(max_temperature_mCelsius,
133                                             temperature_mCelsius);
134       }
135     }
136   }
137 
138   double temperature_Celsius = 0.001 * max_temperature_mCelsius;
139   if (temperature_Celsius < 10.0 || temperature_Celsius > 150.0) {
140     printf("Warning: ignoring temperature reading of %f'C.\n",
141            temperature_Celsius);
142   }
143 
144   return temperature_Celsius;
145 }
146 
GetInitialMachineTemperature()147 const double GetInitialMachineTemperature() {
148   return g_initial_temperature;
149 }
150 
151 // TODO(ihf): update this based on the outcome of crbug.com/356422.
152 // In particular we should probably just have a system script that we can call
153 // and read the output from.
GetMachineTemperature()154 double GetMachineTemperature() {
155   double max_temperature = get_temperature_input();
156   return max_temperature;
157 }
158 
159 // Waits up to timeout seconds to reach cold_temperature in Celsius.
WaitForCoolMachine(double cold_temperature,double timeout,double * temperature)160 double WaitForCoolMachine(double cold_temperature, double timeout,
161                           double *temperature) {
162   // Integer times are in micro-seconds.
163   uint64_t time_start = GetUTime();
164   uint64_t time_now = time_start;
165   uint64_t time_end = time_now + 1e6 * timeout;
166   *temperature = GetMachineTemperature();
167   while (time_now < time_end) {
168     if (*temperature < cold_temperature)
169       break;
170     sleep(1.0);
171     time_now = GetUTime();
172     *temperature = GetMachineTemperature();
173   }
174   double wait_time = 1.0e-6 * (time_now - time_start);
175   assert(wait_time >= 0);
176   assert(wait_time < timeout + 5.0);
177   return wait_time;
178 }
179 
180 namespace glbench {
181 
SetupTexture(GLsizei size_log2)182 GLuint SetupTexture(GLsizei size_log2) {
183   GLsizei size = 1 << size_log2;
184   GLuint name = ~0;
185   glGenTextures(1, &name);
186   glBindTexture(GL_TEXTURE_2D, name);
187   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
188   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
189 
190   unsigned char *pixels = new unsigned char[size * size * 4];
191   if (!pixels)
192     return 0;
193 
194   for (GLint level = 0; size > 0; level++, size /= 2) {
195     unsigned char *p = pixels;
196     for (int i = 0; i < size; i++) {
197       for (int j = 0; j < size; j++) {
198         *p++ = level %3 != 0 ? (i ^ j) << level : 0;
199         *p++ = level %3 != 1 ? (i ^ j) << level : 0;
200         *p++ = level %3 != 2 ? (i ^ j) << level : 0;
201         *p++ = 255;
202       }
203     }
204     if (size == 1) {
205       unsigned char *p = pixels;
206       *p++ = 255;
207       *p++ = 255;
208       *p++ = 255;
209       *p++ = 255;
210     }
211     glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, size, size, 0,
212                  GL_RGBA, GL_UNSIGNED_BYTE, pixels);
213   }
214   delete[] pixels;
215   return name;
216 }
217 
SetupVBO(GLenum target,GLsizeiptr size,const GLvoid * data)218 GLuint SetupVBO(GLenum target, GLsizeiptr size, const GLvoid *data) {
219   GLuint buf = ~0;
220   glGenBuffers(1, &buf);
221   glBindBuffer(target, buf);
222   glBufferData(target, size, data, GL_STATIC_DRAW);
223   CHECK(!glGetError());
224   return buf;
225 }
226 
227 // Generates a lattice symmetric around the origin (all quadrants).
CreateLattice(GLfloat ** vertices,GLsizeiptr * size,GLfloat size_x,GLfloat size_y,int width,int height)228 void CreateLattice(GLfloat **vertices, GLsizeiptr *size,
229                    GLfloat size_x, GLfloat size_y, int width, int height)
230 {
231   GLfloat *vptr = *vertices = new GLfloat[2 * (width + 1) * (height + 1)];
232   GLfloat shift_x = size_x * width;
233   GLfloat shift_y = size_y * height;
234   for (int j = 0; j <= height; j++) {
235     for (int i = 0; i <= width; i++) {
236       *vptr++ = 2 * i * size_x - shift_x;
237       *vptr++ = 2 * j * size_y - shift_y;
238     }
239   }
240   *size = (vptr - *vertices) * sizeof(GLfloat);
241 }
242 
243 // Generates a mesh of 2*width*height triangles.  The ratio of front facing to
244 // back facing triangles is culled_ratio/RAND_MAX.  Returns the number of
245 // vertices in the mesh.
CreateMesh(GLushort ** indices,GLsizeiptr * size,int width,int height,int culled_ratio)246 int CreateMesh(GLushort **indices, GLsizeiptr *size,
247                int width, int height, int culled_ratio) {
248   srand(0);
249 
250   // We use 16 bit indices for compatibility with GL ES
251   CHECK(height * width + width + height <= 65535);
252 
253   GLushort *iptr = *indices = new GLushort[2 * 3 * (width * height)];
254   const int swath_height = 4;
255 
256   CHECK(width % swath_height == 0 && height % swath_height == 0);
257 
258   for (int j = 0; j < height; j += swath_height) {
259     for (int i = 0; i < width; i++) {
260       for (int j2 = 0; j2 < swath_height; j2++) {
261         GLushort first = (j + j2) * (width + 1) + i;
262         GLushort second = first + 1;
263         GLushort third = first + (width + 1);
264         GLushort fourth = third + 1;
265 
266         bool flag = rand() < culled_ratio;
267         *iptr++ = first;
268         *iptr++ = flag ? second : third;
269         *iptr++ = flag ? third : second;
270 
271         *iptr++ = fourth;
272         *iptr++ = flag ? third : second;
273         *iptr++ = flag ? second : third;
274       }
275     }
276   }
277   *size = (iptr - *indices) * sizeof(GLushort);
278 
279   return iptr - *indices;
280 }
281 
print_info_log(int obj,bool shader)282 static void print_info_log(int obj, bool shader)
283 {
284   char info_log[4096];
285   int length;
286 
287   if (shader)
288     glGetShaderInfoLog(obj, sizeof(info_log)-1, &length, info_log);
289   else
290     glGetProgramInfoLog(obj, sizeof(info_log)-1, &length, info_log);
291 
292   char *p = info_log;
293   while (p < info_log + length) {
294     char *newline = strchr(p, '\n');
295     if (newline)
296       *newline = '\0';
297     printf("# Info: glGet%sInfoLog: %s\n", shader ? "Shader" : "Program", p);
298     if (!newline)
299       break;
300     p = newline + 1;
301   }
302 }
303 
print_shader_log(int shader)304 static void print_shader_log(int shader)
305 {
306   print_info_log(shader, true);
307 }
308 
print_program_log(int program)309 static void print_program_log(int program)
310 {
311   print_info_log(program, false);
312 }
313 
314 
InitShaderProgram(const char * vertex_src,const char * fragment_src)315 GLuint InitShaderProgram(const char *vertex_src, const char *fragment_src) {
316   return InitShaderProgramWithHeader(NULL, vertex_src, fragment_src);
317 }
318 
InitShaderProgramWithHeader(const char * header,const char * vertex_src,const char * fragment_src)319 GLuint InitShaderProgramWithHeader(const char* header,
320                                    const char* vertex_src,
321                                    const char* fragment_src) {
322   const char* headers[] = {kGlesHeader, header};
323   return InitShaderProgramWithHeaders(headers,
324                                       arraysize(headers) - (header ? 0 : 1),
325                                       vertex_src, fragment_src);
326 }
327 
InitShaderProgramWithHeaders(const char ** headers,int count,const char * vertex_src,const char * fragment_src)328 GLuint InitShaderProgramWithHeaders(const char** headers,
329                                     int count,
330                                     const char* vertex_src,
331                                     const char* fragment_src) {
332   GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
333   GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
334 
335   const char** header_and_body = new const char*[count + 1];
336   if (count != 0)
337     memcpy(header_and_body, headers, count * sizeof(const char*));
338   header_and_body[count] = vertex_src;
339   glShaderSource(vertex_shader, count + 1, header_and_body, NULL);
340   header_and_body[count] = fragment_src;
341   glShaderSource(fragment_shader, count + 1, header_and_body, NULL);
342   delete[] header_and_body;
343 
344   glCompileShader(vertex_shader);
345   print_shader_log(vertex_shader);
346   glCompileShader(fragment_shader);
347   print_shader_log(fragment_shader);
348 
349   GLuint program = glCreateProgram();
350   glAttachShader(program, vertex_shader);
351   glAttachShader(program, fragment_shader);
352   glLinkProgram(program);
353   print_program_log(program);
354   glUseProgram(program);
355 
356   glDeleteShader(vertex_shader);
357   glDeleteShader(fragment_shader);
358 
359   return program;
360 }
361 
ClearBuffers()362 void ClearBuffers() {
363   glClearColor(1.f, 0, 0, 1.f);
364   glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
365   g_main_gl_interface->SwapBuffers();
366   glClearColor(0, 1.f, 0, 1.f);
367   glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
368   g_main_gl_interface->SwapBuffers();
369   glClearColor(0, 0, 0.f, 1.f);
370 }
371 
372 } // namespace glbench
373