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 };
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
GetInitialMachineTemperature()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.
GetMachineTemperature()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.
WaitForCoolMachine(double cold_temperature,double timeout,double * temperature)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
SetupTexture(GLsizei size_log2)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
SetupVBO(GLenum target,GLsizeiptr size,const GLvoid * data)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).
CreateLattice(GLfloat ** vertices,GLsizeiptr * size,GLfloat size_x,GLfloat size_y,int width,int height)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.
CreateMesh(GLushort ** indices,GLsizeiptr * size,int width,int height,int culled_ratio)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
print_info_log(int obj,bool shader)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
print_shader_log(int shader)298 static void print_shader_log(int shader)
299 {
300 print_info_log(shader, true);
301 }
302
print_program_log(int program)303 static void print_program_log(int program)
304 {
305 print_info_log(program, false);
306 }
307
308
InitShaderProgram(const char * vertex_src,const char * fragment_src)309 GLuint InitShaderProgram(const char *vertex_src, const char *fragment_src) {
310 return InitShaderProgramWithHeader(NULL, vertex_src, fragment_src);
311 }
312
InitShaderProgramWithHeader(const char * header,const char * vertex_src,const char * fragment_src)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
InitShaderProgramWithHeaders(const char ** headers,int count,const char * vertex_src,const char * fragment_src)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
ClearBuffers()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