Latest version of user-report server code

This was SVN commit r9051.
This commit is contained in:
Ykkrosh 2011-03-12 02:36:20 +00:00
parent a0a245d0ec
commit b70a0a5b5a
13 changed files with 380 additions and 68 deletions

View File

@ -0,0 +1,75 @@
glext_versions = {
"GL_EXT_gpu_shader4": "3.0",
"GL_NV_conditional_render": "3.0",
"GL_ARB_color_buffer_float": "3.0",
"GL_ARB_depth_buffer_float": "3.0",
"GL_ARB_texture_float": "3.0",
"GL_EXT_packed_float": "3.0",
"GL_EXT_texture_shared_exponent": "3.0",
"GL_EXT_framebuffer_object": "3.0",
"GL_NV_half_float": "3.0",
"GL_ARB_half_float_pixel": "3.0",
"GL_EXT_framebuffer_multisample": "3.0",
"GL_EXT_framebuffer_blit": "3.0",
"GL_EXT_texture_integer": "3.0",
"GL_EXT_texture_array": "3.0",
"GL_EXT_packed_depth_stencil": "3.0",
"GL_EXT_draw_buffers2": "3.0",
"GL_EXT_texture_compression_rgtc": "3.0",
"GL_EXT_transform_feedback": "3.0",
"GL_APPLE_vertex_array_object": "3.0",
"GL_EXT_framebuffer_sRGB": "3.0",
"GL_ARB_pixel_buffer_object": "2.1",
"GL_EXT_texture_sRGB": "2.1",
"GL_ARB_shader_objects": "2.0",
"GL_ARB_vertex_shader": "2.0",
"GL_ARB_fragment_shader": "2.0",
"GL_ARB_shading_language_100": "2.0",
"GL_ARB_draw_buffers": "2.0",
"GL_ARB_texture_non_power_of_two": "2.0",
"GL_ARB_point_sprite": "2.0",
"GL_EXT_blend_equation_separate": "2.0",
"GL_ARB_vertex_buffer_object": "1.5",
"GL_ARB_occlusion_query": "1.5",
"GL_EXT_shadow_funcs": "1.5",
"GL_SGIS_generate_mipmap": "1.4",
"GL_NV_blend_square": "1.4",
"GL_ARB_depth_texture": "1.4",
"GL_ARB_shadow": "1.4",
"GL_EXT_fog_coord": "1.4",
"GL_EXT_multi_draw_arrays": "1.4",
"GL_ARB_point_parameters": "1.4",
"GL_EXT_secondary_color": "1.4",
"GL_EXT_blend_func_separate": "1.4",
"GL_EXT_stencil_wrap": "1.4",
"GL_ARB_texture_env_crossbar": "1.4",
"GL_EXT_texture_lod_bias": "1.4",
"GL_ARB_texture_mirrored_repeat": "1.4",
"GL_ARB_window_pos": "1.4",
"GL_ARB_texture_compression": "1.3",
"GL_ARB_texture_cube_map": "1.3",
"GL_ARB_multisample": "1.3",
"GL_ARB_multitexture": "1.3",
"GL_ARB_transpose_matrix": "1.3",
"GL_ARB_texture_env_add": "1.3",
"GL_ARB_texture_env_combine": "1.3",
"GL_ARB_texture_env_dot3": "1.3",
"GL_ARB_texture_border_clamp": "1.3",
"GL_EXT_texture3D": "1.2",
"GL_EXT_bgra": "1.2",
"GL_EXT_packed_pixels": "1.2",
"GL_EXT_rescale_normal": "1.2",
"GL_EXT_separate_specular_color": "1.2",
"GL_SGIS_texture_edge_clamp": "1.2",
"GL_SGIS_texture_lod": "1.2",
"GL_EXT_draw_range_elements": "1.2",
"GL_EXT_blend_color": "1.2",
"GL_EXT_blend_minmax": "1.2",
"GL_EXT_blend_subtract": "1.2",
}

View File

@ -1,6 +1,8 @@
from django.db import models
from django.utils import simplejson
import re
class UserReport(models.Model):
uploader = models.IPAddressField(editable = False)
@ -31,6 +33,12 @@ class UserReport(models.Model):
self.cached_json = None
return self.cached_json
def downcast(self):
if self.data_type == 'hwdetect':
return UserReport_hwdetect.objects.get(id = self.id)
else:
return self
class UserReport_hwdetect(UserReport):
class Meta:
@ -48,6 +56,16 @@ class UserReport_hwdetect(UserReport):
os = 'OS X'
return os
def gl_renderer(self):
json = self.data_json()
if json is None or 'GL_RENDERER' not in json:
return None
# The renderer string should typically be interpreted as UTF-8
try:
return json['GL_RENDERER'].encode('iso-8859-1').decode('utf-8')
except UnicodeError:
return json['GL_RENDERER']
def gl_extensions(self):
json = self.data_json()
if json is None or 'GL_EXTENSIONS' not in json:
@ -63,7 +81,72 @@ class UserReport_hwdetect(UserReport):
for (k, v) in json.items():
if not k.startswith('GL_'):
continue
if k in ('GL_RENDERER', 'GL_VENDOR', 'GL_EXTENSIONS'):
if k == 'GL_VERSION':
m = re.match(r'^(\d+\.\d+).*', v)
if m:
limits[k] = '%s [...]' % m.group(1)
continue
if k in ('GL_RENDERER', 'GL_EXTENSIONS'):
continue
# Hide some values that got deleted from the report in r8953, for consistency
if k in ('GL_MAX_COLOR_MATRIX_STACK_DEPTH', 'GL_FRAGMENT_PROGRAM_ARB.GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB', 'GL_FRAGMENT_PROGRAM_ARB.GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB'):
continue
limits[k] = v
return limits
# Construct a nice-looking concise graphics device identifier
# (skipping boring hardware/driver details)
def gl_device_identifier(self):
r = self.gl_renderer()
m = re.match(r'^(?:ATI |Mesa DRI )?(.*?)\s*(?:GEM 20100330 DEVELOPMENT|GEM 20091221 2009Q4|20090101|Series)?\s*(?:x86|/AGP|/PCI|/MMX|/MMX\+|/SSE|/SSE2|/3DNOW!|/3DNow!\+)*(?: TCL| NO-TCL)?(?: DRI2)?$', r)
if m:
r = m.group(1)
return r
# Construct a nice string identifying the driver
def gl_driver(self):
json = self.data_json()
gfx_drv_ver = json['gfx_drv_ver']
# Try the Mesa style first
m = re.match(r'^OpenGL \d+\.\d+(?:\.\d+)? (Mesa .*)$', gfx_drv_ver)
if m:
return m.group(1)
# Try the NVIDIA Linux style
m = re.match(r'^OpenGL \d+\.\d+(?:\.\d+)? NVIDIA (.*)$', gfx_drv_ver)
if m:
return m.group(1)
# Try the ATI Catalyst Linux style
m = re.match(r'^OpenGL (\d+\.\d+\.\d+) Compatibility Profile Context$', gfx_drv_ver)
if m:
return m.group(1)
# Try to guess the relevant Windows driver
# (These are the ones listed in lib/sysdep/os/win/wgfx.cpp)
if json['GL_VENDOR'] == 'NVIDIA Corporation':
# Assume 64-bit takes precedence
m = re.search(r'nvoglv64.dll \((.*?)\)', gfx_drv_ver)
if m: return m.group(1)
m = re.search(r'nvoglv32.dll \((.*?)\)', gfx_drv_ver)
if m: return m.group(1)
m = re.search(r'nvoglnt.dll \((.*?)\)', gfx_drv_ver)
if m: return m.group(1)
if json['GL_VENDOR'] in ('ATI Technologies Inc.', 'Advanced Micro Devices, Inc.'):
m = re.search(r'atioglxx.dll \((.*?)\)', gfx_drv_ver)
if m: return m.group(1)
if json['GL_VENDOR'] == 'Intel':
# Assume 64-bit takes precedence
m = re.search(r'ig4icd64.dll \((.*?)\)', gfx_drv_ver)
if m: return m.group(1)
m = re.search(r'ig4icd32.dll \((.*?)\)', gfx_drv_ver)
if m: return m.group(1)
# Legacy 32-bit
m = re.search(r'iglicd32.dll \((.*?)\)', gfx_drv_ver)
if m: return m.group(1)
return gfx_drv_ver

View File

@ -37,16 +37,22 @@ CPU capabilities
<th>Caches (data/instruction/unified)
<th>TLBs
<th>Feature bits
<th>NUMA
{% for cpu,users in cpus|sortedcpuitems %}
<tr {% cycle 'class=alt' '' %}>
<td>{{ cpu.os }}
<td><nobr>{{ cpu.cpu_identifier }}</nobr>
<td>{{ cpu.x86_vendor }}/{{ cpu.x86_model }}/{{ cpu.x86_family }}
<td>{% if cpu.cpu_frequency = -1 %}?{% else %}{{ cpu.cpu_frequency|cpufreqformat }}{% endif %}
<td>{% if cpu.cpu_frequency = -1 %}{% else %}{{ cpu.cpu_frequency|cpufreqformat }}{% endif %}
<td>{{ cpu.cpu_numpackages }}&times;{{ cpu.cpu_coresperpackage }}&times;{{ cpu.cpu_logicalpercore }}&nbsp;=&nbsp;{{ cpu.cpu_numprocs }}
<td><nobr>{{ cpu.caches|join:"<br>" }}</nobr>
<td><nobr>{{ cpu.tlbs|join:"<br>" }}</nobr>
<td>{% for cap in cpu.caps|sort %}{% if cap in x86_cap_descs %}<abbr title="{{ x86_cap_descs|dictget:cap }}">{{ cap }}</abbr>{% else %}{{ cap }}{% endif %} {% endfor %}
<td>{% if cpu.numa_numnodes != 1 %}<nobr>
Nodes: {{ cpu.numa_numnodes }}<br>
Factor: {{ cpu.numa_factor|floatformat:3 }}<br>
Interleaved: {{ cpu.numa_interleaved }}
</nobr>{% endif %}
{% endfor %}
</table>
{% endblock %}

View File

@ -0,0 +1,29 @@
{% extends "reports/base.html" %}
{% load report_tags %}
{% block content %}
<table>
<tr>
<th>Received
<th>User
<th>gfx_card
<th>gfx_drv_ver
<th>uname_machine
<th>uname_release
<th>uname_sysname
<th>uname_version
{% for report in report_page.object_list %}
{% with json=report.data_json %}
<tr {% cycle 'class=alt' '' %}>
<td>{{ report.upload_date|date:"Y-m-d" }}&nbsp;{{ report.upload_date|date:"H:i:s" }}
<td><a href="{% url userreport.views_private.report_user report.user_id_hash %}"><abbr title="{{ report.user_id_hash }}">{{ report.user_id_hash|slice:"0:8" }}</abbr></a>
<td>{{ json.gfx_card }}
<td>{{ json.gfx_drv_ver }}
<td>{{ json.uname_machine }}
<td>{{ json.uname_release }}
<td>{{ json.uname_sysname }}
<td>{{ json.uname_version }}
{% endwith %}
{% endfor %}
</table>
{% endblock %}

View File

@ -12,10 +12,7 @@ td.false.alt { background: #e22; }
.device-status ul {
margin: 0;
padding: 0;
}
.device-status li {
list-style: none;
padding-left: 2em;
}
{% endblock %}
@ -51,7 +48,7 @@ There is a column for each distinct set of reported features.</p>
<tr><td>
{% for device in devices %}
<th{% safe_cycle ' class=alt' '' %}>
{{ device.0.renderer }} ({{ device.0.os }}):
{{ device.0.device }} ({{ device.0.os }}):
<ul>{% for driver in device.1 %}<li>{{ driver }}{% endfor %}</ul>
{% endfor %}
{% endif %}
@ -68,7 +65,7 @@ There is a column for each distinct set of reported features.</p>
<tr><td>
{% for device in devices %}
<th{% safe_cycle ' class=alt' '' %}>
{{ device.0.renderer }} ({{ device.0.os }}):
{{ device.0.device }} ({{ device.0.os }}):
<ul>{% for driver in device.1 %}<li>{{ driver }}{% endfor %}</ul>
{% endfor %}
{% endif %}
@ -91,4 +88,4 @@ There is a column for each distinct set of reported features.</p>
<input type=submit value="Compare selected devices">
</form>
{% endblock %}
{% endblock %}

View File

@ -59,7 +59,7 @@ OpenGL capabilities report: {{ feature }}
{% for device in values.true|sorteddeviceitems %}
<tr class="data{% safe_cycle '' ' alt'%}">
<td>{{ device.0.vendor }}
<td class=r><a href="{% url userreport.views.report_opengl_device device.0.renderer %}">{{ device.0.renderer }}</a>
<td class=r><a href="{% url userreport.views.report_opengl_device device.0.device %}">{{ device.0.renderer }}</a>
<td>{{ device.0.os }}
<td><ul>
{% for driver in device.1|sort %}<li>{{ driver }}{% endfor %}
@ -78,7 +78,7 @@ OpenGL capabilities report: {{ feature }}
{% for device in values.false|sorteddeviceitems %}
<tr class="data{% safe_cycle '' ' alt'%}">
<td>{{ device.0.vendor }}
<td class=r><a href="{% url userreport.views.report_opengl_device device.0.renderer %}">{{ device.0.renderer }}</a>
<td class=r><a href="{% url userreport.views.report_opengl_device device.0.device %}">{{ device.0.renderer }}</a>
<td>{{ device.0.os }}
<td><ul>
{% for driver in device.1|sort %}<li>{{ driver }}{% endfor %}
@ -105,7 +105,7 @@ OpenGL capabilities report: {{ feature }}
{% for device in values|dictget:val|sorteddeviceitems %}
<tr class="data{% safe_cycle '' ' alt'%}">
<td>{{ device.0.vendor }}
<td class=r><a href="{% url userreport.views.report_opengl_device device.0.renderer %}">{{ device.0.renderer }}</a>
<td class=r><a href="{% url userreport.views.report_opengl_device device.0.device %}">{{ device.0.renderer }}</a>
<td>{{ device.0.os }}
<td><ul>
{% for driver in device.1|sort %}<li>{{ driver }}{% endfor %}
@ -118,4 +118,4 @@ OpenGL capabilities report: {{ feature }}
{% endif %}
{% endblock %}
{% endblock %}

View File

@ -68,6 +68,11 @@ function sort_by_name(ul)
Feel free to do whatever you want with the data.</p>
<p>See the <a href="{% url userreport.views.index %}">index page</a> for more stuff.</p>
<p>The listed extensions are based on the GL_EXTENSIONS string:
we don't show an extension as supported if it's not explicitly advertised,
even if GL_VERSION is a version where that extension was folded into
the main spec.</p>
<div class=col>
<h2>Extension support</h2>
Sort by
@ -79,6 +84,7 @@ Sort by
<span class=progress title="Percentage of devices that support this extension"><span class=bar style="width:{% widthratio ext_devices|dictget:ext|length all_devices|length 40 %}px">{% widthratio ext_devices|dictget:ext|length all_devices|length 100 %}%</span></span>
(<a href="{{ ext|glext_spec_link }}">spec</a>)
<a href="{% url userreport.views.report_opengl_feature ext %}">{{ ext }}</a>
{% if ext in ext_versions %}(~GL{{ ext_versions|dictget:ext }}){% endif %}
{% endfor %}
</ul>
@ -93,10 +99,10 @@ Sort by
<div class=col>
<h2>Device details</h2>
<ul>
{% for device in all_devices %}
<li><a href="{% url userreport.views.report_opengl_device device %}">{{ device }}</a>
{% for device,users in all_devices|sorteditems %}
<li><a href="{% url userreport.views.report_opengl_device device %}">{{ device }}</a> {% if 0 %}({{ users|length }} users){% endif %}
{% endfor %}
</ul>
</div>
{% endblock %}
{% endblock %}

View File

@ -0,0 +1,18 @@
{% extends "reports/base.html" %}
{% load report_tags %}
{% block css %}
{% endblock %}
{% block content %}
{{ data }}
<hr>
???
{% for report in reports %}
{{ report }}
<hr>
{% endfor %}
{% endblock %}

View File

@ -7,6 +7,9 @@ table.profile td {
border-bottom: inherit;
padding: 0 1em 0 0.5em;
}
table.profile td {
white-space: pre;
}
.treemarker {
color: #666;
font-family: monospace;
@ -38,4 +41,4 @@ table.profile td {
{% endwith %}
{% endfor %}
</table>
{% endblock %}
{% endblock %}

View File

@ -82,32 +82,14 @@ def reverse(value):
@register.filter
def format_profile(table):
cols = set()
def extract_cols(t):
for name, row in t.items():
for n in row:
cols.add(n)
if 'children' in row:
extract_cols(row['children'])
extract_cols(table)
if 'children' in cols:
cols.remove('children')
cols = table['cols']
if 'msec/frame' in cols:
cols = ('msec/frame', 'calls/frame', '%/frame', '%/parent', 'mem allocs')
else:
cols = sorted(cols)
out = ['<th>']
out = []
for c in cols:
out.append(u'<th>%s' % conditional_escape(c))
def handle(indents, indent, t):
if 'msec/frame' in cols:
items = [d[1] for d in sorted((-float(r.get('msec/frame', '')), (n,r)) for (n,r) in t.items())]
else:
items = sorted(t.items())
items = sorted(t.items())
item_id = 0
for name, row in items:
@ -118,11 +100,13 @@ def format_profile(table):
item_id += 1
out.append(u'<tr>')
out.append(u'<td><span class=treemarker>%s%s%s╴</span>%s' % (indent, (u'' if last else u''), (u'' if 'children' in row else u''), conditional_escape(name)))
for c in cols:
out.append(u'<td>%s%s' % ('&nbsp;&nbsp;' * indents, conditional_escape(row.get(c, ''))))
if 'children' in row:
handle(indents+1, indent+(u' ' if last else u''), row['children'])
handle(0, u'', table)
out.append(u'<td><span class=treemarker>%s%s%s╴</span>%s' % (indent, (u'' if last else u''), (u'' if row[0] is not None else u''), conditional_escape(name)))
outrow = []
for c in range(1, len(cols)):
outrow.append(u'<td>%s%s' % (' ' * indents, conditional_escape(row[c])))
out.append('%s</td>' % ''.join(outrow))
if row[0] is not None:
handle(indents+1, indent+(u' ' if last else u''), row[0])
handle(0, u'', table['data'])
return mark_safe(u'\n'.join(out))

View File

@ -4,5 +4,7 @@ urlpatterns = patterns('',
(r'^hwdetect/$', 'userreport.views_private.report_hwdetect'),
(r'^messages/$', 'userreport.views_private.report_messages'),
(r'^profile/$', 'userreport.views_private.report_profile'),
(r'^performance/$', 'userreport.views_private.report_performance'),
(r'^gfx/$', 'userreport.views_private.report_gfx'),
(r'^user/([0-9a-f]+)$', 'userreport.views_private.report_user'),
)

View File

@ -1,5 +1,6 @@
from userreport.models import UserReport, UserReport_hwdetect
import userreport.x86 as x86
import userreport.gl
import hashlib
import datetime
@ -102,15 +103,20 @@ def report_cpu(request):
else:
return '%d-way' % w
def fmt_cache(c):
def fmt_cache(c, t):
types = ('?', 'D', 'I ', 'U')
return "L%d %s: %s (%s, shared %dx, %dB line)" % (
if c['type'] == 0:
return "(Unknown %s cache)" % t
return "L%d %s: %s (%s, shared %dx%s)" % (
c['level'], types[c['type']], fmt_size(c['totalsize']),
fmt_assoc(c['associativity']), c['sharedby'], c['linesize']
fmt_assoc(c['associativity']), c['sharedby'],
('' if c['linesize'] == 64 else ', %dB line' % c['linesize'])
)
def fmt_tlb(c):
def fmt_tlb(c, t):
types = ('?', 'D', 'I ', 'U')
if c['type'] == 0:
return "(Unknown %s TLB)" % t
return "L%d %s: %d-entry (%s, %s page)" % (
c['level'], types[c['type']], c['entries'],
fmt_assoc(c['associativity']), fmt_size(c['pagesize'])
@ -121,16 +127,16 @@ def report_cpu(request):
icaches = i[:]
caches = []
while len(dcaches) or len(icaches):
if len(dcaches) and len(icaches) and dcaches[0] == icaches[0]:
caches.append(cb(dcaches[0]))
if len(dcaches) and len(icaches) and dcaches[0] == icaches[0] and dcaches[0]['type'] == 3:
caches.append(cb(dcaches[0], 'U'))
dcaches.pop(0)
icaches.pop(0)
else:
if len(dcaches):
caches.append(cb(dcaches[0]))
caches.append(cb(dcaches[0], 'D'))
dcaches.pop(0)
if len(icaches):
caches.append(cb(icaches[0]))
caches.append(cb(icaches[0], 'I'))
icaches.pop(0)
return tuple(caches)
@ -168,29 +174,26 @@ def report_opengl_json(request):
exts = report.gl_extensions()
limits = report.gl_limits()
devices.setdefault(hashabledict({'vendor': json['GL_VENDOR'], 'renderer': json['GL_RENDERER'], 'os': report.os()}), {}).setdefault((hashabledict(limits), exts), set()).add(json['gfx_drv_ver'])
devices.setdefault(hashabledict({'renderer': report.gl_renderer(), 'os': report.os()}), {}).setdefault((hashabledict(limits), exts), set()).add(report.gl_driver())
distinct_devices = []
for (renderer, v) in devices.items():
for (caps, versions) in v.items():
distinct_devices.append((renderer, sorted(versions), caps))
distinct_devices.sort(key = lambda x: (x[0]['vendor'], x[0]['renderer'], x[0]['os'], x))
distinct_devices.sort(key = lambda x: (x[0]['renderer'], x[0]['os'], x))
data = []
for r,vs,(limits,exts) in distinct_devices:
data.append({'device': r, 'versions': vs, 'limits': limits, 'extensions': sorted(exts)})
data.append({'device': r, 'drivers': vs, 'limits': limits, 'extensions': sorted(exts)})
json = simplejson.dumps(data, indent=1, sort_keys=True)
return HttpResponse(json, content_type = 'text/plain')
def device_identifier(json):
return json['GL_RENDERER']
def report_opengl_index(request):
reports = get_hwdetect_reports()
all_limits = set()
all_exts = set()
all_devices = set()
all_devices = {}
ext_devices = {}
for report in reports:
@ -198,8 +201,8 @@ def report_opengl_index(request):
if json is None:
continue
device = device_identifier(json)
all_devices.add(device)
device = report.gl_device_identifier()
all_devices.setdefault(device, set()).add(report.user_id_hash)
exts = report.gl_extensions()
all_exts |= exts
@ -211,13 +214,13 @@ def report_opengl_index(request):
all_limits = sorted(all_limits)
all_exts = sorted(all_exts)
all_devices = sorted(all_devices)
return render_to_response('reports/opengl_index.html', {
'all_limits': all_limits,
'all_exts': all_exts,
'all_devices': all_devices,
'ext_devices': ext_devices,
'ext_versions': userreport.gl.glext_versions,
})
def report_opengl_feature(request, feature):
@ -232,6 +235,7 @@ def report_opengl_feature(request, feature):
if json is None:
continue
device = report.gl_device_identifier()
exts = report.gl_extensions()
limits = hashabledict(report.gl_limits())
@ -243,7 +247,7 @@ def report_opengl_feature(request, feature):
val = limits[feature]
all_values.add(val)
values.setdefault(val, {}).setdefault(hashabledict({'vendor': json['GL_VENDOR'], 'renderer': json['GL_RENDERER'], 'os': report.os()}), set()).add(json['gfx_drv_ver'])
values.setdefault(val, {}).setdefault(hashabledict({'vendor': json['GL_VENDOR'], 'renderer': report.gl_renderer(), 'os': report.os(), 'device': device}), set()).add(report.gl_driver())
if values.keys() == [None]:
raise Http404
@ -274,7 +278,7 @@ def report_opengl_devices(request, selected):
if json is None:
continue
device = device_identifier(json)
device = report.gl_device_identifier()
all_devices.add(device)
if device not in selected:
continue
@ -285,7 +289,7 @@ def report_opengl_devices(request, selected):
limits = report.gl_limits()
all_limits |= set(limits.keys())
devices.setdefault(hashabledict({'vendor': json['GL_VENDOR'], 'renderer': json['GL_RENDERER'], 'os': report.os()}), {}).setdefault((hashabledict(limits), exts), set()).add(json['gfx_drv_ver'])
devices.setdefault(hashabledict({'device': report.gl_device_identifier(), 'os': report.os()}), {}).setdefault((hashabledict(limits), exts), set()).add(report.gl_driver())
if len(selected) == 1 and len(devices) == 0:
raise Http404
@ -297,7 +301,7 @@ def report_opengl_devices(request, selected):
for (renderer, v) in devices.items():
for (caps, versions) in v.items():
distinct_devices.append((renderer, sorted(versions), caps))
distinct_devices.sort(key = lambda x: (x[0]['vendor'], x[0]['renderer'], x[0]['os'], x))
distinct_devices.sort(key = lambda x: (x[0]['device'], x))
return render_to_response('reports/opengl_device.html', {
'selected': selected,

View File

@ -1,9 +1,13 @@
from userreport.models import UserReport
from django.http import HttpResponseForbidden
from django.http import HttpResponse, HttpResponseForbidden
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.core.paginator import Paginator, InvalidPage, EmptyPage
from django.db.models import Q
import re
import numpy
def render_reports(request, reports, template, args):
paginator = Paginator(reports, args.get('pagesize', 100))
@ -34,7 +38,7 @@ def report_messages(request):
def report_profile(request):
reports = UserReport.objects.order_by('-upload_date')
reports = reports.filter(data_type = 'profile', data_version__gte = 1)
reports = reports.filter(data_type = 'profile', data_version__gte = 2)
return render_reports(request, reports, 'reports/profile.html', {'pagesize': 20})
@ -43,3 +47,104 @@ def report_hwdetect(request):
reports = reports.filter(data_type = 'hwdetect', data_version__gte = 1)
return render_reports(request, reports, 'reports/hwdetect.html', {})
def report_gfx(request):
reports = UserReport.objects.order_by('-upload_date')
reports = reports.filter(data_type = 'hwdetect', data_version__gte = 1)
return render_reports(request, reports, 'reports/gfx.html', {'pagesize': 1000})
def report_performance(request):
reports = UserReport.objects.order_by('upload_date')
reports = reports.filter(
Q(data_type = 'hwdetect', data_version__gte = 5) |
Q(data_type = 'profile', data_version__gte = 1)
)
def summarise_hwdetect(report):
json = report.data_json()
return {
'cpu_identifier': json['cpu_identifier'],
'device': report.gl_device_identifier(),
'build_debug': json['build_debug'],
'build_revision': json['build_revision'],
'build_datetime': json['build_datetime'],
'gfx_res': (json['video_xres'], json['video_yres']),
}
def summarise_profile(report):
json = report.data_json()
msecs = None
for name,table in json['profiler'].items():
m = re.match(r'Profiling Information for: root \(Time in node: (\d+\.\d+) msec/frame\)', name)
if m:
#msecs = m.group(1)
try:
if report.data_version == 1:
msecs = float(table['render']['msec/frame'])
else:
msecs = float(table['data']['render'][2])
except KeyError:
pass
# TODO: get the render time?
# TODO: get shadow, water settings
return {
'msecs': msecs,
'map': json['map'],
'time': json['time'],
# 'json': json
}
profiles = []
last_hwdetect = {}
for report in reports:
if report.data_type == 'hwdetect':
last_hwdetect[report.user_id_hash] = summarise_hwdetect(report.downcast())
elif report.data_type == 'profile':
if report.user_id_hash in last_hwdetect:
profiles.append([report.user_id_hash, last_hwdetect[report.user_id_hash], summarise_profile(report)])
datapoints = {}
for user,hwdetect,profile in profiles:
if hwdetect['build_debug']:
continue
# if profile['time'] != 60:
# continue
if profile['msecs'] is None or float(profile['msecs']) == 0:
continue
datapoints.setdefault(hwdetect['device'], []).append(profile['msecs'])
# return render_to_response('reports/performance.html', {'data': datapoints, 'reports': profiles})
sorted_datapoints = sorted(datapoints.items(), key = lambda (k,v):
-numpy.median(v)
)
data_boxplot = [ v for k,v in sorted_datapoints ]
data_scatter = ([], [])
for i in range(len(data_boxplot)):
for x in data_boxplot[i]:
data_scatter[0].append(i+1)
data_scatter[1].append(x)
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
fig = Figure(figsize=(16,16))
ax = fig.add_subplot(111)
fig.subplots_adjust(left = 0.05, right = 0.99, top = 0.99, bottom = 0.2)
ax.boxplot(data_boxplot, sym = '')
ax.scatter(data_scatter[0], data_scatter[1], marker='x')
ax.set_ylim(1, 10000)
ax.set_yscale('log')
ax.set_ylabel('Render time (msecs)')
ax.set_xticklabels([k for k,v in sorted_datapoints], rotation=90, fontsize=8)
canvas = FigureCanvas(fig)
response = HttpResponse(content_type = 'image/png')
canvas.print_png(response, dpi=80)
return response