// Pre-declare private functions used before definitions (jslint)
init_vars, updateState, init_msg, normal_msg, recv_message,
- framebufferUpdate,
+ framebufferUpdate, print_stats,
pixelFormat, clientEncodings, fbUpdateRequest,
keyEvent, pointerEvent, clientCutText,
encHandlers = {},
encNames = {},
+ encStats = {}, // [rectCnt, rectCntTot]
ws = null, // Web Socket object
canvas = null, // Canvas object
for (i=0; i < encodings.length; i+=1) {
encHandlers[encodings[i][1]] = encHandlers[encodings[i][0]];
encNames[encodings[i][1]] = encodings[i][0];
+ encStats[encodings[i][1]] = [0, 0];
}
// Initialize canvas
try {
FBU.imgQ = []; // TIGHT_PNG image queue
mouse_buttonMask = 0;
mouse_arr = [];
+
+ // Clear the per connection encoding stats
+ for (i=0; i < encodings.length; i+=1) {
+ encStats[encodings[i][1]][0] = 0;
+ }
+};
+
+// Print statistics
+print_stats = function() {
+ var i, encName, s;
+ Util.Info("Encoding stats for this connection:");
+ for (i=0; i < encodings.length; i+=1) {
+ s = encStats[encodings[i][1]];
+ if ((s[0] + s[1]) > 0) {
+ Util.Info(" " + encodings[i][0] + ": " +
+ s[0] + " rects");
+ }
+ }
+ Util.Info("Encoding stats since page load:");
+ for (i=0; i < encodings.length; i+=1) {
+ s = encStats[encodings[i][1]];
+ if ((s[0] + s[1]) > 0) {
+ Util.Info(" " + encodings[i][0] + ": "
+ + s[1] + " rects");
+ }
+ }
};
//
}, conf.disconnectTimeout * 1000);
}
+ print_stats();
+
// WebSocket.onclose transitions to 'disconnected'
break;
};
framebufferUpdate = function() {
- var now, hdr, fbu_rt_diff, last_bytes, last_rects, ret = true;
+ var now, hdr, fbu_rt_diff, ret = true, ctx;
if (FBU.rects === 0) {
//Util.Debug("New FBU: rQ.slice(0,20): " + rQ.slice(0,20));
}
timing.last_fbu = (new Date()).getTime();
- last_bytes = rQlen();
- last_rects = FBU.rects;
- // false ret means need more data
ret = encHandlers[FBU.encoding]();
now = (new Date()).getTime();
timing.cur_fbu += (now - timing.last_fbu);
+ if (ret) {
+ encStats[FBU.encoding][0] += 1;
+ encStats[FBU.encoding][1] += 1;
+ }
+
if (FBU.rects === 0) {
if (((FBU.width === fb_width) &&
(FBU.height === fb_height)) ||
//
encHandlers.RAW = function display_raw() {
- //Util.Debug(">> display_raw");
+ //Util.Debug(">> display_raw (" + rQlen() + " bytes)");
var cur_y, cur_height;
FBU.rects -= 1;
FBU.bytes = 0;
}
+ //Util.Debug("<< display_raw (" + rQlen() + " bytes)");
return true;
};
--- /dev/null
+<html>
+ <head>
+ <title>VNC Performance Benchmark</title>
+ <link rel="stylesheet" href="include/plain.css">
+ </head>
+ <body>
+
+ Passes: <input id='passes' style='width:50' value=3>
+
+ <input id='startButton' type='button' value='Start' style='width:100px'
+ onclick="start();" disabled>
+
+ <br><br>
+
+ Results:<br>
+ <textarea id="messages" style="font-size: 9;" cols=80 rows=15></textarea>
+
+ <br><br>
+
+ <div id="VNC_screen">
+ <div id="VNC_status_bar" class="VNC_status_bar" style="margin-top: 0px;">
+ <table border=0 width=100%><tr>
+ <td><div id="VNC_status">Loading</div></td>
+ </tr></table>
+ </div>
+ <canvas id="VNC_canvas" width="640px" height="20px">
+ Canvas not supported.
+ </canvas>
+ </div>
+
+ </body>
+
+ <!--
+ <script type='text/javascript'
+ src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
+ -->
+
+ <script src="include/vnc.js"></script>
+ <script src="include/playback.js"></script>
+ <script src="data_multi.js"></script>
+
+ <script>
+ var start_time, VNC_frame_data, pass, passes, encIdx,
+ encOrder = ['raw', 'rre', 'hextile', 'tightpng', 'copyrect'],
+ encTot = {}, encMin = {}, encMax = {},
+ passCur, passTot, passMin, passMax;
+
+ function msg(str) {
+ console.log(str);
+ var cell = $('messages');
+ cell.innerHTML += str + "\n";
+ cell.scrollTop = cell.scrollHeight;
+ }
+ function dbgmsg(str) {
+ if (Util.get_logging() === 'debug') {
+ msg(str);
+ }
+ }
+
+ updateState = function (rfb, state, oldstate, mesg) {
+ switch (state) {
+ case 'failed':
+ case 'fatal':
+ msg("noVNC sent '" + state +
+ "' state during pass " + pass +
+ ", iteration " + iteration +
+ " frame " + frame_idx);
+ test_state = 'failed';
+ break;
+ case 'loaded':
+ $('startButton').disabled = false;
+ break;
+ }
+ if (typeof mesg !== 'undefined') {
+ $('VNC_status').innerHTML = mesg;
+ }
+ }
+
+ function start() {
+ $('startButton').value = "Running";
+ $('startButton').disabled = true;
+
+ mode = 'perftest'; // full-speed
+ passes = $('passes').value;
+ pass = 1;
+ encIdx = 0;
+
+ // Render each encoding once for each pass
+ iterations = 1;
+
+ // Initialize stats counters
+ for (i = 0; i < encOrder.length; i++) {
+ enc = encOrder[i];
+ encTot[i] = 0;
+ encMin[i] = 2<<23; // Something sufficiently large
+ encMax[i] = 0;
+ }
+ passCur = 0;
+ passTot = 0;
+ passMin = 2<<23;
+ passMax = 0;
+
+ // Fire away
+ next_encoding();
+ }
+
+ function next_encoding() {
+ var encName;
+
+ if (encIdx >= encOrder.length) {
+ // Accumulate pass stats
+ if (passCur < passMin) {
+ passMin = passCur;
+ }
+ if (passCur > passMax) {
+ passMax = passCur;
+ }
+ msg("Pass " + pass + " took " + passCur + " ms");
+
+ passCur = 0;
+ encIdx = 0;
+ pass += 1;
+ if (pass > passes) {
+ // We are finished
+ rfb.get_canvas().stop(); // Shut-off event interception
+ $('startButton').disabled = false;
+ $('startButton').value = "Start";
+ finish_passes();
+ return; // We are finished, terminate
+ }
+ }
+
+ encName = encOrder[encIdx];
+ dbgmsg("Rendering pass " + pass + " encoding '" + encName + "'");
+
+ VNC_frame_data = VNC_frame_data_multi[encName];
+ iteration = 0;
+ start_time = (new Date()).getTime();
+
+ next_iteration();
+ }
+
+ // Finished rendering current encoding
+ function finish() {
+ var total_time, end_time = (new Date()).getTime();
+ total_time = end_time - start_time;
+
+ dbgmsg("Encoding " + encOrder[encIdx] + " took " + total_time + "ms");
+
+ passCur += total_time;
+ passTot += total_time;
+
+ // Accumulate stats
+ encTot[encIdx] += total_time;
+ if (total_time < encMin[encIdx]) {
+ encMin[encIdx] = total_time;
+ }
+ if (total_time > encMax[encIdx]) {
+ encMax[encIdx] = total_time;
+ }
+
+ encIdx += 1;
+ next_encoding();
+ }
+
+ function finish_passes() {
+ var i, enc, avg, passAvg;
+ msg("STATS (for " + passes + " passes)");
+ // Encoding stats
+ for (i = 0; i < encOrder.length; i++) {
+ enc = encOrder[i];
+ avg = (encTot[i] / passes).toFixed(1);
+ msg(" " + enc + ": " + encTot[i] + " ms, " +
+ encMin[i] + "/" + avg + "/" + encMax[i] +
+ " (min/avg/max)");
+
+ }
+ // Print pass stats
+ passAvg = (passTot / passes).toFixed(1);
+ msg("\n All passes: " + passTot + " ms, " +
+ passMin + "/" + passAvg + "/" + passMax +
+ " (min/avg/max)");
+ }
+
+ window.onload = function() {
+ var i, enc;
+ dbgmsg("Frame lengths:");
+ for (i = 0; i < encOrder.length; i++) {
+ enc = encOrder[i];
+ dbgmsg(" " + enc + ": " + VNC_frame_data_multi[enc].length);
+ }
+ rfb = RFB({'target': 'VNC_canvas',
+ 'updateState': updateState});
+ rfb.testMode(send_array);
+ }
+ </script>
+</html>
cpartial = cpartial + buf
def proxy_handler(client):
- global target_host, target_port, options, rec
+ global target_host, target_port, options, rec, fname
if settings['record']:
- handler_msg("opening record file: %s" % settings['record'])
- rec = open("%s.%s" % (settings['record'],
- settings['handler_id']), 'w+')
+ fname = "%s.%s" % (settings['record'],
+ settings['handler_id'])
+ handler_msg("opening record file: %s" % fname)
+ rec = open(fname, 'w+')
rec.write("var VNC_frame_data = [\n")
handler_msg("connecting to: %s:%s" % (target_host, target_port))