diff --git a/include/rfb.js b/include/rfb.js index 38812704618772e71610cc9d35f5cd7620aba907..dd073894a60261f7300403e6e52c6012d62d019b 100644 --- a/include/rfb.js +++ b/include/rfb.js @@ -18,7 +18,7 @@ var that = {}, // Public API interface // 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, @@ -61,6 +61,7 @@ var that = {}, // Public API interface encHandlers = {}, encNames = {}, + encStats = {}, // [rectCnt, rectCntTot] ws = null, // Web Socket object canvas = null, // Canvas object @@ -216,6 +217,7 @@ function constructor() { 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 { @@ -309,6 +311,32 @@ init_vars = function() { 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"); + } + } }; // @@ -440,6 +468,8 @@ updateState = function(state, statusMsg) { }, conf.disconnectTimeout * 1000); } + print_stats(); + // WebSocket.onclose transitions to 'disconnected' break; @@ -944,7 +974,7 @@ normal_msg = function() { }; 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)); @@ -1011,15 +1041,17 @@ framebufferUpdate = function() { } 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)) || @@ -1058,7 +1090,7 @@ framebufferUpdate = function() { // encHandlers.RAW = function display_raw() { - //Util.Debug(">> display_raw"); + //Util.Debug(">> display_raw (" + rQlen() + " bytes)"); var cur_y, cur_height; @@ -1084,6 +1116,7 @@ encHandlers.RAW = function display_raw() { FBU.rects -= 1; FBU.bytes = 0; } + //Util.Debug("<< display_raw (" + rQlen() + " bytes)"); return true; }; diff --git a/tests/vnc_perf.html b/tests/vnc_perf.html new file mode 100644 index 0000000000000000000000000000000000000000..8e9c925b0f5d1af3fd73267e44921915067fb141 --- /dev/null +++ b/tests/vnc_perf.html @@ -0,0 +1,197 @@ +<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> diff --git a/utils/wsproxy.py b/utils/wsproxy.py index 2615c3c4974ff9353f8bf242687f47eb737da542..71fe5774295ed46ef98263204a3854c5decea60f 100755 --- a/utils/wsproxy.py +++ b/utils/wsproxy.py @@ -101,12 +101,13 @@ def do_proxy(client, target): 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))