1 /**************************************************************************/
2 /* */
3 /* Copyright (c) 2001, 2010 NoMachine, http://www.nomachine.com/. */
4 /* */
5 /* NXCOMP, NX protocol compression and NX extensions to this software */
6 /* are copyright of NoMachine. Redistribution and use of the present */
7 /* software is allowed according to terms specified in the file LICENSE */
8 /* which comes in the source distribution. */
9 /* */
10 /* Check http://www.nomachine.com/licensing.html for applicability. */
11 /* */
12 /* NX and NoMachine are trademarks of Medialogic S.p.A. */
13 /* */
14 /* All rights reserved. */
15 /* */
16 /**************************************************************************/
17
18 #include <stdio.h>
19
20 #include "Statistics.h"
21
22 #include "Control.h"
23
24 #include "Proxy.h"
25
26 #include "ClientStore.h"
27 #include "ServerStore.h"
28
29 //
30 // Length of temporary buffer
31 // used to format output.
32 //
33
34 #define FORMAT_LENGTH 1024
35
36 //
37 // Log level.
38 //
39
40 #define PANIC
41 #define WARNING
42 #undef TEST
43 #undef DEBUG
44
45 //
46 // Note that when presenting statistics we invert the
47 // correct semantics of X client and server entities.
48 // This is questionable, but matches the user's pers-
49 // pective of running remote X applications on its
50 // local client.
51 //
52
Statistics(Proxy * proxy)53 Statistics::Statistics(Proxy *proxy) : proxy_(proxy)
54 {
55 transportPartial_.idleTime_ = 0;
56 transportPartial_.readTime_ = 0;
57 transportPartial_.writeTime_ = 0;
58 transportPartial_.proxyBytesIn_ = 0;
59 transportPartial_.proxyBytesOut_ = 0;
60 transportPartial_.proxyFramesIn_ = 0;
61 transportPartial_.proxyFramesOut_ = 0;
62 transportPartial_.proxyWritesOut_ = 0;
63 transportPartial_.compressedBytesIn_ = 0;
64 transportPartial_.compressedBytesOut_ = 0;
65 transportPartial_.decompressedBytesIn_ = 0;
66 transportPartial_.decompressedBytesOut_ = 0;
67 transportPartial_.framingBitsOut_ = 0;
68
69 transportTotal_.idleTime_ = 0;
70 transportTotal_.readTime_ = 0;
71 transportTotal_.writeTime_ = 0;
72 transportTotal_.proxyBytesIn_ = 0;
73 transportTotal_.proxyBytesOut_ = 0;
74 transportTotal_.proxyFramesIn_ = 0;
75 transportTotal_.proxyFramesOut_ = 0;
76 transportTotal_.proxyWritesOut_ = 0;
77 transportTotal_.compressedBytesIn_ = 0;
78 transportTotal_.compressedBytesOut_ = 0;
79 transportTotal_.decompressedBytesIn_ = 0;
80 transportTotal_.decompressedBytesOut_ = 0;
81 transportTotal_.framingBitsOut_ = 0;
82
83 for (int i = 0; i < STATISTICS_OPCODE_MAX; i++)
84 {
85 protocolPartial_.requestCached_[i] = 0;
86 protocolPartial_.requestReplied_[i] = 0;
87 protocolPartial_.requestCount_[i] = 0;
88 protocolPartial_.requestBitsIn_[i] = 0;
89 protocolPartial_.requestBitsOut_[i] = 0;
90
91 protocolPartial_.renderRequestCached_[i] = 0;
92 protocolPartial_.renderRequestCount_[i] = 0;
93 protocolPartial_.renderRequestBitsIn_[i] = 0;
94 protocolPartial_.renderRequestBitsOut_[i] = 0;
95
96 protocolPartial_.replyCached_[i] = 0;
97 protocolPartial_.replyCount_[i] = 0;
98 protocolPartial_.replyBitsIn_[i] = 0;
99 protocolPartial_.replyBitsOut_[i] = 0;
100
101 protocolPartial_.eventCached_[i] = 0;
102 protocolPartial_.eventCount_[i] = 0;
103 protocolPartial_.eventBitsIn_[i] = 0;
104 protocolPartial_.eventBitsOut_[i] = 0;
105
106 protocolTotal_.requestCached_[i] = 0;
107 protocolTotal_.requestReplied_[i] = 0;
108 protocolTotal_.requestCount_[i] = 0;
109 protocolTotal_.requestBitsIn_[i] = 0;
110 protocolTotal_.requestBitsOut_[i] = 0;
111
112 protocolTotal_.renderRequestCached_[i] = 0;
113 protocolTotal_.renderRequestCount_[i] = 0;
114 protocolTotal_.renderRequestBitsIn_[i] = 0;
115 protocolTotal_.renderRequestBitsOut_[i] = 0;
116
117 protocolTotal_.replyCached_[i] = 0;
118 protocolTotal_.replyCount_[i] = 0;
119 protocolTotal_.replyBitsIn_[i] = 0;
120 protocolTotal_.replyBitsOut_[i] = 0;
121
122 protocolTotal_.eventCached_[i] = 0;
123 protocolTotal_.eventCount_[i] = 0;
124 protocolTotal_.eventBitsIn_[i] = 0;
125 protocolTotal_.eventBitsOut_[i] = 0;
126 }
127
128 protocolPartial_.cupsCount_ = 0;
129 protocolPartial_.cupsBitsIn_ = 0;
130 protocolPartial_.cupsBitsOut_ = 0;
131
132 protocolPartial_.smbCount_ = 0;
133 protocolPartial_.smbBitsIn_ = 0;
134 protocolPartial_.smbBitsOut_ = 0;
135
136 protocolPartial_.mediaCount_ = 0;
137 protocolPartial_.mediaBitsIn_ = 0;
138 protocolPartial_.mediaBitsOut_ = 0;
139
140 protocolPartial_.httpCount_ = 0;
141 protocolPartial_.httpBitsIn_ = 0;
142 protocolPartial_.httpBitsOut_ = 0;
143
144 protocolPartial_.fontCount_ = 0;
145 protocolPartial_.fontBitsIn_ = 0;
146 protocolPartial_.fontBitsOut_ = 0;
147
148 protocolPartial_.slaveCount_ = 0;
149 protocolPartial_.slaveBitsIn_ = 0;
150 protocolPartial_.slaveBitsOut_ = 0;
151
152 protocolTotal_.cupsCount_ = 0;
153 protocolTotal_.cupsBitsIn_ = 0;
154 protocolTotal_.cupsBitsOut_ = 0;
155
156 protocolTotal_.smbCount_ = 0;
157 protocolTotal_.smbBitsIn_ = 0;
158 protocolTotal_.smbBitsOut_ = 0;
159
160 protocolTotal_.mediaCount_ = 0;
161 protocolTotal_.mediaBitsIn_ = 0;
162 protocolTotal_.mediaBitsOut_ = 0;
163
164 protocolTotal_.httpCount_ = 0;
165 protocolTotal_.httpBitsIn_ = 0;
166 protocolTotal_.httpBitsOut_ = 0;
167
168 protocolTotal_.fontCount_ = 0;
169 protocolTotal_.fontBitsIn_ = 0;
170 protocolTotal_.fontBitsOut_ = 0;
171
172 protocolTotal_.slaveCount_ = 0;
173 protocolTotal_.slaveBitsIn_ = 0;
174 protocolTotal_.slaveBitsOut_ = 0;
175
176 packedPartial_.packedBytesIn_ = 0;
177 packedPartial_.packedBytesOut_ = 0;
178
179 packedTotal_.packedBytesIn_ = 0;
180 packedTotal_.packedBytesOut_ = 0;
181
182 splitPartial_.splitCount_ = 0;
183 splitPartial_.splitAborted_ = 0;
184 splitPartial_.splitAbortedBytesOut_ = 0;
185
186 splitTotal_.splitCount_ = 0;
187 splitTotal_.splitAborted_ = 0;
188 splitTotal_.splitAbortedBytesOut_ = 0;
189
190 overallPartial_.overallBytesIn_ = 0;
191 overallPartial_.overallBytesOut_ = 0;
192
193 overallTotal_.overallBytesIn_ = 0;
194 overallTotal_.overallBytesOut_ = 0;
195
196 proxyData_.protocolCount_ = 0;
197 proxyData_.controlCount_ = 0;
198 proxyData_.splitCount_ = 0;
199 proxyData_.dataCount_ = 0;
200
201 proxyData_.streamRatio_ = 1;
202
203 startShortFrameTs_ = getTimestamp();
204 startLongFrameTs_ = getTimestamp();
205 startFrameTs_ = getTimestamp();
206
207 bytesInShortFrame_ = 0;
208 bytesInLongFrame_ = 0;
209
210 bitrateInShortFrame_ = 0;
211 bitrateInLongFrame_ = 0;
212
213 topBitrate_ = 0;
214
215 congestionInFrame_ = 0;
216 }
217
~Statistics()218 Statistics::~Statistics()
219 {
220 }
221
resetPartialStats()222 int Statistics::resetPartialStats()
223 {
224 transportPartial_.idleTime_ = 0;
225 transportPartial_.readTime_ = 0;
226 transportPartial_.writeTime_ = 0;
227 transportPartial_.proxyBytesIn_ = 0;
228 transportPartial_.proxyBytesOut_ = 0;
229 transportPartial_.proxyFramesIn_ = 0;
230 transportPartial_.proxyFramesOut_ = 0;
231 transportPartial_.proxyWritesOut_ = 0;
232 transportPartial_.compressedBytesIn_ = 0;
233 transportPartial_.compressedBytesOut_ = 0;
234 transportPartial_.decompressedBytesIn_ = 0;
235 transportPartial_.decompressedBytesOut_ = 0;
236 transportPartial_.framingBitsOut_ = 0;
237
238 for (int i = 0; i < STATISTICS_OPCODE_MAX; i++)
239 {
240 protocolPartial_.requestCached_[i] = 0;
241 protocolPartial_.requestReplied_[i] = 0;
242 protocolPartial_.requestCount_[i] = 0;
243 protocolPartial_.requestBitsIn_[i] = 0;
244 protocolPartial_.requestBitsOut_[i] = 0;
245
246 protocolPartial_.renderRequestCached_[i] = 0;
247 protocolPartial_.renderRequestCount_[i] = 0;
248 protocolPartial_.renderRequestBitsIn_[i] = 0;
249 protocolPartial_.renderRequestBitsOut_[i] = 0;
250
251 protocolPartial_.replyCached_[i] = 0;
252 protocolPartial_.replyCount_[i] = 0;
253 protocolPartial_.replyBitsIn_[i] = 0;
254 protocolPartial_.replyBitsOut_[i] = 0;
255
256 protocolPartial_.eventCached_[i] = 0;
257 protocolPartial_.eventCount_[i] = 0;
258 protocolPartial_.eventBitsIn_[i] = 0;
259 protocolPartial_.eventBitsOut_[i] = 0;
260 }
261
262 protocolPartial_.cupsCount_ = 0;
263 protocolPartial_.cupsBitsIn_ = 0;
264 protocolPartial_.cupsBitsOut_ = 0;
265
266 protocolPartial_.smbCount_ = 0;
267 protocolPartial_.smbBitsIn_ = 0;
268 protocolPartial_.smbBitsOut_ = 0;
269
270 protocolPartial_.mediaCount_ = 0;
271 protocolPartial_.mediaBitsIn_ = 0;
272 protocolPartial_.mediaBitsOut_ = 0;
273
274 protocolPartial_.httpCount_ = 0;
275 protocolPartial_.httpBitsIn_ = 0;
276 protocolPartial_.httpBitsOut_ = 0;
277
278 protocolPartial_.fontCount_ = 0;
279 protocolPartial_.fontBitsIn_ = 0;
280 protocolPartial_.fontBitsOut_ = 0;
281
282 protocolPartial_.slaveCount_ = 0;
283 protocolPartial_.slaveBitsIn_ = 0;
284 protocolPartial_.slaveBitsOut_ = 0;
285
286 packedPartial_.packedBytesIn_ = 0;
287 packedPartial_.packedBytesOut_ = 0;
288
289 splitPartial_.splitCount_ = 0;
290 splitPartial_.splitAborted_ = 0;
291 splitPartial_.splitAbortedBytesOut_ = 0;
292
293 overallPartial_.overallBytesIn_ = 0;
294 overallPartial_.overallBytesOut_ = 0;
295
296 return 1;
297 }
298
addCompressedBytes(unsigned int bytesIn,unsigned int bytesOut)299 void Statistics::addCompressedBytes(unsigned int bytesIn, unsigned int bytesOut)
300 {
301 transportPartial_.compressedBytesIn_ += bytesIn;
302 transportTotal_.compressedBytesIn_ += bytesIn;
303
304 transportPartial_.compressedBytesOut_ += bytesOut;
305 transportTotal_.compressedBytesOut_ += bytesOut;
306
307 double ratio = bytesIn / bytesOut;
308
309 if (ratio < 1)
310 {
311 ratio = 1;
312 }
313
314 #if defined(TEST) || defined(TOKEN)
315 *logofs << "Statistics: TOKEN! Old ratio was "
316 << proxyData_.streamRatio_ << " current is "
317 << (double) ratio << " new ratio is " << (double)
318 ((proxyData_.streamRatio_ * 2) + ratio) / 3 << ".\n"
319 << logofs_flush;
320 #endif
321
322 proxyData_.streamRatio_ = ((proxyData_.streamRatio_ * 2) + ratio) / 3;
323
324 #if defined(TEST) || defined(TOKEN)
325 *logofs << "Statistics: TOKEN! Updated compressed bytes "
326 << "with " << bytesIn << " in " << bytesOut << " out "
327 << "and ratio " << (double) proxyData_.streamRatio_
328 << ".\n" << logofs_flush;
329 #endif
330 }
331
332 //
333 // Recalculate the current bitrate. The bytes written
334 // are accounted at the time the transport actually
335 // writes the data to the network, not at the time it
336 // receives the data from the upper layers. The reason
337 // is that data can be compressed by the stream com-
338 // pressor, so we can become aware of the new bitrate
339 // only afer having flushed the ZLIB stream. This also
340 // means that, to have a reliable estimate, we need to
341 // flush the link often.
342 //
343
updateBitrate(int bytes)344 void Statistics::updateBitrate(int bytes)
345 {
346 T_timestamp thisFrameTs = getNewTimestamp();
347
348 int diffFramesInMs = diffTimestamp(startFrameTs_, thisFrameTs);
349
350 #ifdef DEBUG
351 *logofs << "Statistics: Difference since previous timestamp is "
352 << diffFramesInMs << " Ms.\n" << logofs_flush;
353 #endif
354
355 if (diffFramesInMs > 0)
356 {
357 #ifdef DEBUG
358 *logofs << "Statistics: Removing " << diffFramesInMs
359 << " Ms in short and long time frame.\n"
360 << logofs_flush;
361 #endif
362
363 int shortBytesToRemove = (int) (((double) bytesInShortFrame_ * (double) diffFramesInMs) /
364 (double) control -> ShortBitrateTimeFrame);
365
366 int longBytesToRemove = (int) (((double) bytesInLongFrame_ * (double) diffFramesInMs) /
367 (double) control -> LongBitrateTimeFrame);
368
369 #ifdef DEBUG
370 *logofs << "Statistics: Removing " << shortBytesToRemove
371 << " bytes from " << bytesInShortFrame_
372 << " in the short frame.\n" << logofs_flush;
373 #endif
374
375 bytesInShortFrame_ -= shortBytesToRemove;
376
377 if (bytesInShortFrame_ < 0)
378 {
379 #ifdef TEST
380 *logofs << "Statistics: Bytes in short frame are "
381 << bytesInShortFrame_ << ". Set to 0.\n"
382 << logofs_flush;
383 #endif
384
385 bytesInShortFrame_ = 0;
386 }
387
388 #ifdef DEBUG
389 *logofs << "Statistics: Removing " << longBytesToRemove
390 << " bytes from " << bytesInLongFrame_
391 << " in the long frame.\n" << logofs_flush;
392 #endif
393
394 bytesInLongFrame_ -= longBytesToRemove;
395
396 if (bytesInLongFrame_ < 0)
397 {
398 #ifdef TEST
399 *logofs << "Statistics: Bytes in long frame are "
400 << bytesInLongFrame_ << ". Set to 0.\n"
401 << logofs_flush;
402 #endif
403
404 bytesInLongFrame_ = 0;
405 }
406
407 int diffStartInMs;
408
409 diffStartInMs = diffTimestamp(thisFrameTs, startShortFrameTs_);
410
411 if (diffStartInMs > control -> ShortBitrateTimeFrame)
412 {
413 addMsTimestamp(startShortFrameTs_, diffStartInMs);
414 }
415
416 diffStartInMs = diffTimestamp(thisFrameTs, startLongFrameTs_);
417
418 if (diffStartInMs > control -> LongBitrateTimeFrame)
419 {
420 addMsTimestamp(startLongFrameTs_, diffStartInMs);
421 }
422
423 startFrameTs_ = thisFrameTs;
424 }
425
426 #ifdef DEBUG
427 *logofs << "Statistics: Adding " << bytes << " bytes to "
428 << bytesInShortFrame_ << " in the short frame.\n"
429 << logofs_flush;
430 #endif
431
432 bytesInShortFrame_ = bytesInShortFrame_ + bytes;
433
434 #ifdef DEBUG
435 *logofs << "Statistics: Adding " << bytes << " bytes to "
436 << bytesInLongFrame_ << " in the long frame.\n"
437 << logofs_flush;
438 #endif
439
440 bytesInLongFrame_ = bytesInLongFrame_ + bytes;
441
442 bitrateInShortFrame_ = (int) ((double) bytesInShortFrame_ /
443 ((double) control -> ShortBitrateTimeFrame / 1000));
444
445 bitrateInLongFrame_ = (int) ((double) bytesInLongFrame_ /
446 ((double) control -> LongBitrateTimeFrame / 1000));
447
448 if (bitrateInShortFrame_ > topBitrate_)
449 {
450 topBitrate_ = bitrateInShortFrame_;
451 }
452
453 #ifdef TEST
454 *logofs << "Statistics: Current bitrate is short " << bitrateInShortFrame_
455 << " long " << bitrateInLongFrame_ << " top " << topBitrate_
456 << ".\n" << logofs_flush;
457 #endif
458 }
459
updateCongestion(int remaining,int limit)460 void Statistics::updateCongestion(int remaining, int limit)
461 {
462 #ifdef TEST
463 *logofs << "Statistics: Updating the congestion "
464 << "counters at " << strMsTimestamp()
465 << ".\n" << logofs_flush;
466 #endif
467
468 double current = remaining;
469
470 if (current < 0)
471 {
472 current = 0;
473 }
474
475 current = 9 * (limit - current) / limit;
476
477 #ifdef TEST
478 *logofs << "Statistics: Current congestion is "
479 << current << " with " << limit << " tokens "
480 << "and " << remaining << " remaining.\n"
481 << logofs_flush;
482 #endif
483
484 //
485 // If the current congestion counter is greater
486 // than the previous, take the current value,
487 // otherwise ramp down the value by calculating
488 // the average of the last 8 updates.
489 //
490
491 #ifdef TEST
492 *logofs << "Statistics: Old congestion was "
493 << congestionInFrame_;
494 #endif
495
496 if (current >= congestionInFrame_)
497 {
498 congestionInFrame_ = current;
499 }
500 else
501 {
502 congestionInFrame_ = ((congestionInFrame_ * 7) + current) / 8;
503 }
504
505 #ifdef TEST
506 *logofs << " new congestion is "
507 << ((congestionInFrame_ * 7) + current) / 8
508 << ".\n" << logofs_flush;
509 #endif
510
511 //
512 // Call the function with 0 bytes flushed
513 // so the agent can update its congestion
514 // counter.
515 //
516
517 FlushCallback(0);
518 }
519
getClientCacheStats(int type,char * & buffer)520 int Statistics::getClientCacheStats(int type, char *&buffer)
521 {
522 if (type != PARTIAL_STATS && type != TOTAL_STATS)
523 {
524 #ifdef PANIC
525 *logofs << "Statistics: PANIC! Cannot produce statistics "
526 << "with qualifier '" << type << "'.\n"
527 << logofs_flush;
528 #endif
529
530 return -1;
531 }
532
533 //
534 // Print message cache data according
535 // to local and remote view.
536 //
537
538 MessageStore *currentStore = NULL;
539 MessageStore *anyStore = NULL;
540
541 char format[FORMAT_LENGTH];
542
543 strcat(buffer, "\nNX Cache Statistics\n");
544 strcat(buffer, "-------------------\n\n");
545
546 for (int m = proxy_client; m <= proxy_server; m++)
547 {
548 if (m == proxy_client)
549 {
550 strcat(buffer, "Request\tCached\tSize at Server\t\tSize at Client\t\tCache limit\n");
551 strcat(buffer, "-------\t------\t--------------\t\t--------------\t\t-----------\n");
552 }
553 else
554 {
555 strcat(buffer, "\nReply\tCached\tSize at Server\t\tSize at Client\t\tCache limit\n");
556 strcat(buffer, "-----\t------\t--------------\t\t--------------\t\t-----------\n");
557 }
558
559 for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++)
560 {
561 if (m == proxy_client)
562 {
563 currentStore = proxy_ -> getClientStore() -> getRequestStore(i);
564 }
565 else
566 {
567 currentStore = proxy_ -> getServerStore() -> getReplyStore(i);
568 }
569
570 if (currentStore != NULL &&
571 (currentStore -> getLocalStorageSize() ||
572 currentStore -> getRemoteStorageSize()))
573 {
574 anyStore = currentStore;
575
576 sprintf(format, "#%d\t%d\t", i, currentStore -> getSize());
577
578 strcat(buffer, format);
579
580 sprintf(format, "%d (%.0f KB)\t\t", currentStore -> getLocalStorageSize(),
581 ((double) currentStore -> getLocalStorageSize()) / 1024);
582
583 strcat(buffer, format);
584
585 sprintf(format, "%d (%.0f KB)\t\t", currentStore -> getRemoteStorageSize(),
586 ((double) currentStore -> getRemoteStorageSize()) / 1024);
587
588 strcat(buffer, format);
589
590 sprintf(format, "%d/%.0f KB\n", currentStore -> cacheSlots,
591 ((double) control -> getUpperStorageSize() / 100 *
592 currentStore -> cacheThreshold) / 1024);
593
594 strcat(buffer, format);
595 }
596 }
597
598 if (anyStore == NULL)
599 {
600 strcat(buffer, "N/A\n");
601 }
602 }
603
604 if (anyStore != NULL)
605 {
606 sprintf(format, "\ncache: %d bytes (%d KB) available at server.\n",
607 control -> ClientTotalStorageSize,
608 control -> ClientTotalStorageSize / 1024);
609
610 strcat(buffer, format);
611
612 sprintf(format, " %d bytes (%d KB) available at client.\n\n",
613 control -> ServerTotalStorageSize,
614 control -> ServerTotalStorageSize / 1024);
615
616 strcat(buffer, format);
617
618 sprintf(format, " %d bytes (%d KB) allocated at server.\n",
619 anyStore -> getLocalTotalStorageSize(),
620 anyStore -> getLocalTotalStorageSize() / 1024);
621
622 strcat(buffer, format);
623
624 sprintf(format, " %d bytes (%d KB) allocated at client.\n\n\n",
625 anyStore -> getRemoteTotalStorageSize(),
626 anyStore -> getRemoteTotalStorageSize() / 1024);
627
628 strcat(buffer, format);
629 }
630 else
631 {
632 strcat(buffer, "\ncache: N/A\n\n");
633 }
634
635 return 1;
636 }
637
getClientProtocolStats(int type,char * & buffer)638 int Statistics::getClientProtocolStats(int type, char *&buffer)
639 {
640 if (type != PARTIAL_STATS && type != TOTAL_STATS)
641 {
642 #ifdef PANIC
643 *logofs << "Statistics: PANIC! Cannot produce statistics "
644 << "with qualifier '" << type << "'.\n"
645 << logofs_flush;
646 #endif
647
648 return -1;
649 }
650
651 struct T_transportData *transportData;
652 struct T_protocolData *protocolData;
653 struct T_overallData *overallData;
654
655 if (type == PARTIAL_STATS)
656 {
657 transportData = &transportPartial_;
658 protocolData = &protocolPartial_;
659 overallData = &overallPartial_;
660 }
661 else
662 {
663 transportData = &transportTotal_;
664 protocolData = &protocolTotal_;
665 overallData = &overallTotal_;
666 }
667
668 char format[FORMAT_LENGTH];
669
670 double countRequestIn = 0;
671 double countCachedRequestIn = 0;
672 double countRepliedRequestIn = 0;
673
674 double countRequestBitsIn = 0;
675 double countRequestBitsOut = 0;
676
677 double countAnyIn = 0;
678 double countBitsIn = 0;
679 double countBitsOut = 0;
680
681 //
682 // Print request data.
683 //
684
685 strcat(buffer, "NX Server Side Protocol Statistics\n");
686 strcat(buffer, "----------------------------------\n\n");
687
688 //
689 // Print render data.
690 //
691
692 strcat(buffer, "Render Total\tCached\tBits In\t\tBits Out\tBits/Request\t\tRatio\n");
693 strcat(buffer, "------- -----\t------\t-------\t\t--------\t------------\t\t-----\n");
694
695 for (int i = 0; i < STATISTICS_OPCODE_MAX; i++)
696 {
697 if (protocolData -> renderRequestCount_[i])
698 {
699 sprintf(format, "#%d ", i);
700
701 while (strlen(format) < 8)
702 {
703 strcat(format, " ");
704 }
705
706 strcat(buffer, format);
707
708 if (protocolData -> renderRequestCached_[i] > 0)
709 {
710 sprintf(format, "%.0f\t%.0f", protocolData -> renderRequestCount_[i],
711 protocolData -> renderRequestCached_[i]);
712 }
713 else
714 {
715 sprintf(format, "%.0f\t", protocolData -> renderRequestCount_[i]);
716 }
717
718 strcat(buffer, format);
719
720 sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t",
721 protocolData -> renderRequestBitsIn_[i], protocolData -> renderRequestBitsIn_[i] / 8192,
722 protocolData -> renderRequestBitsOut_[i], protocolData -> renderRequestBitsOut_[i] / 8192,
723 protocolData -> renderRequestBitsIn_[i] / protocolData -> renderRequestCount_[i],
724 protocolData -> renderRequestBitsOut_[i] / protocolData -> renderRequestCount_[i]);
725
726 strcat(buffer, format);
727
728 if (protocolData -> renderRequestBitsOut_[i] > 0)
729 {
730 sprintf(format, "%5.3f:1\n", protocolData -> renderRequestBitsIn_[i] /
731 protocolData -> renderRequestBitsOut_[i]);
732
733 strcat(buffer, format);
734 }
735 else
736 {
737 strcat(buffer, "1:1\n");
738 }
739 }
740
741 countRequestIn += protocolData -> renderRequestCount_[i];
742 countCachedRequestIn += protocolData -> renderRequestCached_[i];
743
744 countRequestBitsIn += protocolData -> renderRequestBitsIn_[i];
745 countRequestBitsOut += protocolData -> renderRequestBitsOut_[i];
746
747 countAnyIn += protocolData -> renderRequestCount_[i];
748 countBitsIn += protocolData -> renderRequestBitsIn_[i];
749 countBitsOut += protocolData -> renderRequestBitsOut_[i];
750 }
751
752 if (countRequestIn > 0)
753 {
754 if (countCachedRequestIn > 0)
755 {
756 sprintf(format, "\ntotal: %.0f\t%.0f", countRequestIn, countCachedRequestIn);
757 }
758 else
759 {
760 sprintf(format, "\ntotal: %.0f\t", countRequestIn);
761 }
762
763 strcat(buffer, format);
764
765 sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t",
766 countRequestBitsIn, countRequestBitsIn / 8192, countRequestBitsOut,
767 countRequestBitsOut / 8192, countRequestBitsIn / countRequestIn,
768 countRequestBitsOut / countRequestIn);
769
770 strcat(buffer, format);
771
772 if (countRequestBitsOut > 0)
773 {
774 sprintf(format, "%5.3f:1\n", countRequestBitsIn / countRequestBitsOut);
775 }
776 else
777 {
778 sprintf(format, "1:1\n");
779 }
780
781 strcat(buffer, format);
782 }
783 else
784 {
785 strcat(buffer, "N/A\n\n");
786 }
787
788 countRequestIn = 0;
789 countCachedRequestIn = 0;
790
791 countRequestBitsIn = 0;
792 countRequestBitsOut = 0;
793
794 countAnyIn = 0;
795 countBitsIn = 0;
796 countBitsOut = 0;
797
798 //
799 // Print other requests' data.
800 //
801
802 strcat(buffer, "\nRequest Total\tCached\tBits In\t\tBits Out\tBits/Request\t\tRatio\n");
803 strcat(buffer, "------- -----\t------\t-------\t\t--------\t------------\t\t-----\n");
804
805 for (int i = 0; i < STATISTICS_OPCODE_MAX; i++)
806 {
807 if (protocolData -> requestCount_[i])
808 {
809 sprintf(format, "#%d ", i);
810
811 while (strlen(format) < 5)
812 {
813 strcat(format, " ");
814 }
815
816 //
817 // Mark NX agent-related requests, those
818 // having a reply and finally those that
819 // have been probably tainted by client
820 // side.
821 //
822
823 if (i >= X_NXFirstOpcode && i <= X_NXLastOpcode)
824 {
825 strcat(format, "A");
826 }
827
828 if (i != X_NXInternalGenericReply && protocolData -> requestReplied_[i] > 0)
829 {
830 strcat(format, "R");
831 }
832
833 if (i == X_NoOperation && control -> TaintReplies)
834 {
835 strcat(format, "T");
836 }
837
838 while (strlen(format) < 8)
839 {
840 strcat(format, " ");
841 }
842
843 strcat(buffer, format);
844
845 if (protocolData -> requestCached_[i] > 0)
846 {
847 sprintf(format, "%.0f\t%.0f", protocolData -> requestCount_[i],
848 protocolData -> requestCached_[i]);
849 }
850 else
851 {
852 sprintf(format, "%.0f\t", protocolData -> requestCount_[i]);
853 }
854
855 strcat(buffer, format);
856
857 sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t",
858 protocolData -> requestBitsIn_[i], protocolData -> requestBitsIn_[i] / 8192,
859 protocolData -> requestBitsOut_[i], protocolData -> requestBitsOut_[i] / 8192,
860 protocolData -> requestBitsIn_[i] / protocolData -> requestCount_[i],
861 protocolData -> requestBitsOut_[i] / protocolData -> requestCount_[i]);
862
863 strcat(buffer, format);
864
865 if (protocolData -> requestBitsOut_[i] > 0)
866 {
867 sprintf(format, "%5.3f:1\n", protocolData -> requestBitsIn_[i] /
868 protocolData -> requestBitsOut_[i]);
869
870 strcat(buffer, format);
871 }
872 else
873 {
874 strcat(buffer, "1:1\n");
875 }
876 }
877
878 countRequestIn += protocolData -> requestCount_[i];
879 countCachedRequestIn += protocolData -> requestCached_[i];
880 countRepliedRequestIn += protocolData -> requestReplied_[i];
881
882 countRequestBitsIn += protocolData -> requestBitsIn_[i];
883 countRequestBitsOut += protocolData -> requestBitsOut_[i];
884
885 countAnyIn += protocolData -> requestCount_[i];
886 countBitsIn += protocolData -> requestBitsIn_[i];
887 countBitsOut += protocolData -> requestBitsOut_[i];
888 }
889
890 if (countRequestIn > 0)
891 {
892 if (countCachedRequestIn > 0)
893 {
894 sprintf(format, "\ntotal: %.0f\t%.0f", countRequestIn, countCachedRequestIn);
895 }
896 else
897 {
898 sprintf(format, "\ntotal: %.0f\t", countRequestIn);
899 }
900
901 strcat(buffer, format);
902
903 sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t",
904 countRequestBitsIn, countRequestBitsIn / 8192, countRequestBitsOut,
905 countRequestBitsOut / 8192, countRequestBitsIn / countRequestIn,
906 countRequestBitsOut / countRequestIn);
907
908 strcat(buffer, format);
909
910 if (countRequestBitsOut > 0)
911 {
912 sprintf(format, "%5.3f:1\n", countRequestBitsIn / countRequestBitsOut);
913 }
914 else
915 {
916 sprintf(format, "1:1\n");
917 }
918
919 strcat(buffer, format);
920 }
921 else
922 {
923 strcat(buffer, "N/A\n\n");
924 }
925
926 //
927 // Print transport data.
928 //
929
930 getTimeStats(type, buffer);
931
932 countAnyIn += protocolData -> cupsCount_;
933 countBitsIn += protocolData -> cupsBitsIn_;
934 countBitsOut += protocolData -> cupsBitsOut_;
935
936 countAnyIn += protocolData -> smbCount_;
937 countBitsIn += protocolData -> smbBitsIn_;
938 countBitsOut += protocolData -> smbBitsOut_;
939
940 countAnyIn += protocolData -> mediaCount_;
941 countBitsIn += protocolData -> mediaBitsIn_;
942 countBitsOut += protocolData -> mediaBitsOut_;
943
944 countAnyIn += protocolData -> httpCount_;
945 countBitsIn += protocolData -> httpBitsIn_;
946 countBitsOut += protocolData -> httpBitsOut_;
947
948 countAnyIn += protocolData -> fontCount_;
949 countBitsIn += protocolData -> fontBitsIn_;
950 countBitsOut += protocolData -> fontBitsOut_;
951
952 countAnyIn += protocolData -> slaveCount_;
953 countBitsIn += protocolData -> slaveBitsIn_;
954 countBitsOut += protocolData -> slaveBitsOut_;
955
956 //
957 // Save the overall amount of bytes
958 // coming from X clients.
959 //
960
961 overallData -> overallBytesIn_ = countBitsIn / 8;
962
963 //
964 // Print performance data.
965 //
966
967 if (transportData -> readTime_ > 0)
968 {
969 sprintf(format, " %.0f messages (%.0f KB) encoded per second.\n\n",
970 countAnyIn / (transportData -> readTime_ / 1000),
971 (countBitsIn + transportData -> framingBitsOut_) / 8192 /
972 (transportData -> readTime_ / 1000));
973 }
974 else
975 {
976 sprintf(format, " %.0f messages (%.0f KB) encoded per second.\n\n",
977 countAnyIn, (countBitsIn + transportData ->
978 framingBitsOut_) / 8192);
979 }
980
981 strcat(buffer, format);
982
983 strcat(buffer, "link: ");
984
985 //
986 // ZLIB compression stats.
987 //
988
989 getStreamStats(type, buffer);
990
991 //
992 // Save the overall amount of bytes
993 // sent on NX proxy link.
994 //
995
996 if (transportData -> compressedBytesOut_ > 0)
997 {
998 overallData -> overallBytesOut_ = transportData -> compressedBytesOut_;
999 }
1000 else
1001 {
1002 overallData -> overallBytesOut_ = countBitsOut / 8;
1003 }
1004
1005 //
1006 // Print info on multiplexing overhead.
1007 //
1008
1009 getFramingStats(type, buffer);
1010
1011 //
1012 // Print stats about additional channels.
1013 //
1014
1015 getServicesStats(type, buffer);
1016
1017 //
1018 // Compression summary.
1019 //
1020
1021 double ratio = 1;
1022
1023 if (transportData -> compressedBytesOut_ / 1024 > 0)
1024 {
1025 ratio = ((countBitsIn + transportData -> framingBitsOut_) / 8192) /
1026 (transportData -> compressedBytesOut_ / 1024);
1027
1028 }
1029 else if (countBitsOut > 0)
1030 {
1031 ratio = (countBitsIn + transportData -> framingBitsOut_) /
1032 countBitsOut;
1033 }
1034
1035 sprintf(format, " Protocol compression ratio is %5.3f:1.\n\n",
1036 ratio);
1037
1038 strcat(buffer, format);
1039
1040 getBitrateStats(type, buffer);
1041
1042 getSplitStats(type, buffer);
1043
1044 sprintf(format, " %.0f total handled replies (%.0f unmatched).\n\n\n",
1045 countRepliedRequestIn, protocolData -> requestReplied_[X_NXInternalGenericReply]);
1046
1047 strcat(buffer, format);
1048
1049 return 1;
1050 }
1051
getClientOverallStats(int type,char * & buffer)1052 int Statistics::getClientOverallStats(int type, char *&buffer)
1053 {
1054 if (type != PARTIAL_STATS && type != TOTAL_STATS)
1055 {
1056 #ifdef PANIC
1057 *logofs << "Statistics: PANIC! Cannot produce statistics "
1058 << "with qualifier '" << type << "'.\n"
1059 << logofs_flush;
1060 #endif
1061
1062 return -1;
1063 }
1064
1065 struct T_overallData *overallData;
1066 struct T_packedData *packedData;
1067
1068 if (type == PARTIAL_STATS)
1069 {
1070 overallData = &overallPartial_;
1071 packedData = &packedPartial_;
1072 }
1073 else
1074 {
1075 overallData = &overallTotal_;
1076 packedData = &packedTotal_;
1077 }
1078
1079 char format[FORMAT_LENGTH];
1080
1081 //
1082 // Print header including link type,
1083 // followed by info on packed images.
1084 //
1085
1086 strcat(buffer, "NX Compression Summary\n");
1087 strcat(buffer, "----------------------\n\n");
1088
1089 char label[FORMAT_LENGTH];
1090
1091 switch (control -> LinkMode)
1092 {
1093 case LINK_TYPE_NONE:
1094 {
1095 strcpy(label, "NONE");
1096
1097 break;
1098 }
1099 case LINK_TYPE_MODEM:
1100 {
1101 strcpy(label, "MODEM");
1102
1103 break;
1104 }
1105 case LINK_TYPE_ISDN:
1106 {
1107 strcpy(label, "ISDN");
1108
1109 break;
1110 }
1111 case LINK_TYPE_ADSL:
1112 {
1113 strcpy(label, "ADSL");
1114
1115 break;
1116 }
1117 case LINK_TYPE_WAN:
1118 {
1119 strcpy(label, "WAN");
1120
1121 break;
1122 }
1123 case LINK_TYPE_LAN:
1124 {
1125 strcpy(label, "LAN");
1126
1127 break;
1128 }
1129 default:
1130 {
1131 strcpy(label, "Unknown");
1132
1133 break;
1134 }
1135 }
1136
1137 sprintf(format, "link: %s", label);
1138
1139 if (control -> LocalDeltaCompression == 1)
1140 {
1141 strcat(format, " with protocol compression enabled.");
1142 }
1143 else
1144 {
1145 strcat(format, " with protocol compression disabled.");
1146 }
1147
1148 strcat(format, "\n\n");
1149
1150 strcat(buffer, format);
1151
1152 if (packedData -> packedBytesIn_ > 0)
1153 {
1154 sprintf(format, "images: %.0f bytes (%.0f KB) packed to %.0f (%.0f KB).\n\n",
1155 packedData -> packedBytesOut_, packedData -> packedBytesOut_ / 1024,
1156 packedData -> packedBytesIn_, packedData -> packedBytesIn_ / 1024);
1157
1158 strcat(buffer, format);
1159
1160 sprintf(format, " Images compression ratio is %5.3f:1.\n\n",
1161 packedData -> packedBytesOut_ / packedData -> packedBytesIn_);
1162
1163 strcat(buffer, format);
1164 }
1165
1166 double overallIn = overallData -> overallBytesIn_ - packedData -> packedBytesIn_ +
1167 packedData -> packedBytesOut_;
1168
1169 double overallOut = overallData -> overallBytesOut_;
1170
1171 sprintf(format, "overall: %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n",
1172 overallIn, overallIn / 1024, overallOut, overallOut / 1024);
1173
1174 strcat(buffer, format);
1175
1176 if (overallData -> overallBytesOut_ > 0)
1177 {
1178 sprintf(format, " Overall NX server compression ratio is %5.3f:1.\n\n\n",
1179 overallIn / overallOut);
1180 }
1181 else
1182 {
1183 sprintf(format, " Overall NX server compression ratio is 1:1.\n\n\n");
1184 }
1185
1186 strcat(buffer, format);
1187
1188 return 1;
1189 }
1190
getServerCacheStats(int type,char * & buffer)1191 int Statistics::getServerCacheStats(int type, char *&buffer)
1192 {
1193 if (type != PARTIAL_STATS && type != TOTAL_STATS)
1194 {
1195 #ifdef PANIC
1196 *logofs << "Statistics: PANIC! Cannot produce statistics "
1197 << "with qualifier '" << type << "'.\n"
1198 << logofs_flush;
1199 #endif
1200
1201 return -1;
1202 }
1203
1204 //
1205 // Print message cache data according
1206 // to local and remote view.
1207 //
1208
1209 MessageStore *currentStore = NULL;
1210 MessageStore *anyStore = NULL;
1211
1212 char format[FORMAT_LENGTH];
1213
1214 strcat(buffer, "\nNX Cache Statistics\n");
1215 strcat(buffer, "-------------------\n\n");
1216
1217 for (int m = proxy_client; m <= proxy_server; m++)
1218 {
1219 if (m == proxy_client)
1220 {
1221 strcat(buffer, "Request\tCached\tSize at Server\t\tSize at Client\t\tCache limit\n");
1222 strcat(buffer, "-------\t------\t--------------\t\t--------------\t\t-----------\n");
1223 }
1224 else
1225 {
1226 strcat(buffer, "\nReply\tCached\tSize at Server\t\tSize at Client\t\tCache limit\n");
1227 strcat(buffer, "-----\t------\t--------------\t\t--------------\t\t-----------\n");
1228 }
1229
1230 for (int i = 0; i < CHANNEL_STORE_OPCODE_LIMIT; i++)
1231 {
1232 if (m == proxy_client)
1233 {
1234 currentStore = proxy_ -> getClientStore() -> getRequestStore(i);
1235 }
1236 else
1237 {
1238 currentStore = proxy_ -> getServerStore() -> getReplyStore(i);
1239 }
1240
1241 if (currentStore != NULL &&
1242 (currentStore -> getLocalStorageSize() ||
1243 currentStore -> getRemoteStorageSize()))
1244 {
1245 anyStore = currentStore;
1246
1247 sprintf(format, "#%d\t%d\t", i, currentStore -> getSize());
1248
1249 strcat(buffer, format);
1250
1251 sprintf(format, "%d (%.0f KB)\t\t", currentStore -> getRemoteStorageSize(),
1252 ((double) currentStore -> getRemoteStorageSize()) / 1024);
1253
1254 strcat(buffer, format);
1255
1256 sprintf(format, "%d (%.0f KB)\t\t", currentStore -> getLocalStorageSize(),
1257 ((double) currentStore -> getLocalStorageSize()) / 1024);
1258
1259 strcat(buffer, format);
1260
1261 sprintf(format, "%d/%.0f KB\n", currentStore -> cacheSlots,
1262 ((double) control -> getUpperStorageSize() / 100 *
1263 currentStore -> cacheThreshold) / 1024);
1264
1265 strcat(buffer, format);
1266 }
1267 }
1268
1269 if (anyStore == NULL)
1270 {
1271 strcat(buffer, "N/A\n");
1272 }
1273 }
1274
1275 if (anyStore != NULL)
1276 {
1277 sprintf(format, "\ncache: %d bytes (%d KB) available at server.\n",
1278 control -> ClientTotalStorageSize,
1279 control -> ClientTotalStorageSize / 1024);
1280
1281 strcat(buffer, format);
1282
1283 sprintf(format, " %d bytes (%d KB) available at client.\n\n",
1284 control -> ServerTotalStorageSize,
1285 control -> ServerTotalStorageSize / 1024);
1286
1287 strcat(buffer, format);
1288
1289 sprintf(format, " %d bytes (%d KB) allocated at server.\n",
1290 anyStore -> getRemoteTotalStorageSize(),
1291 anyStore -> getRemoteTotalStorageSize() / 1024);
1292
1293 strcat(buffer, format);
1294
1295 sprintf(format, " %d bytes (%d KB) allocated at client.\n\n\n",
1296 anyStore -> getLocalTotalStorageSize(),
1297 anyStore -> getLocalTotalStorageSize() / 1024);
1298
1299 strcat(buffer, format);
1300 }
1301 else
1302 {
1303 strcat(buffer, "\ncache: N/A\n\n");
1304 }
1305
1306 return 1;
1307 }
1308
getServerProtocolStats(int type,char * & buffer)1309 int Statistics::getServerProtocolStats(int type, char *&buffer)
1310 {
1311 if (type != PARTIAL_STATS && type != TOTAL_STATS)
1312 {
1313 #ifdef PANIC
1314 *logofs << "Statistics: PANIC! Cannot produce statistics "
1315 << "with qualifier '" << type << "'.\n"
1316 << logofs_flush;
1317 #endif
1318
1319 return -1;
1320 }
1321
1322 struct T_transportData *transportData;
1323 struct T_protocolData *protocolData;
1324 struct T_overallData *overallData;
1325
1326 if (type == PARTIAL_STATS)
1327 {
1328 transportData = &transportPartial_;
1329 protocolData = &protocolPartial_;
1330 overallData = &overallPartial_;
1331 }
1332 else
1333 {
1334 transportData = &transportTotal_;
1335 protocolData = &protocolTotal_;
1336 overallData = &overallTotal_;
1337 }
1338
1339 char format[FORMAT_LENGTH];
1340
1341 double countReplyBitsIn = 0;
1342 double countReplyBitsOut = 0;
1343
1344 double countReplyIn = 0;
1345 double countCachedReplyIn = 0;
1346
1347 double countEventBitsIn = 0;
1348 double countEventBitsOut = 0;
1349
1350 double countEventIn = 0;
1351 double countCachedEventIn = 0;
1352
1353 double countAnyIn = 0;
1354 double countBitsIn = 0;
1355 double countBitsOut = 0;
1356
1357 //
1358 // Print reply data.
1359 //
1360
1361 strcat(buffer, "NX Client Side Protocol Statistics\n");
1362 strcat(buffer, "----------------------------------\n\n");
1363
1364 strcat(buffer, "Reply Total\tCached\tBits In\t\tBits Out\tBits/Reply\t\tRatio\n");
1365 strcat(buffer, "------- -----\t------\t-------\t\t--------\t----------\t\t-----\n");
1366
1367 for (int i = 0; i < STATISTICS_OPCODE_MAX; i++)
1368 {
1369 if (protocolData -> replyCount_[i])
1370 {
1371 sprintf(format, "#%d ", i);
1372
1373 while (strlen(format) < 5)
1374 {
1375 strcat(format, " ");
1376 }
1377
1378 //
1379 // Mark replies originated
1380 // by NX agent requests.
1381 //
1382
1383 if (i >= X_NXFirstOpcode && i <= X_NXLastOpcode)
1384 {
1385 strcat(format, "A");
1386 }
1387
1388 //
1389 // Mark replies that we didn't
1390 // match against a request.
1391 //
1392
1393 if (i == 1)
1394 {
1395 strcat(format, "U");
1396 }
1397
1398 while (strlen(format) < 8)
1399 {
1400 strcat(format, " ");
1401 }
1402
1403 strcat(buffer, format);
1404
1405 if (protocolData -> replyCached_[i] > 0)
1406 {
1407 sprintf(format, "%.0f\t%.0f", protocolData -> replyCount_[i],
1408 protocolData -> replyCached_[i]);
1409 }
1410 else
1411 {
1412 sprintf(format, "%.0f\t", protocolData -> replyCount_[i]);
1413 }
1414
1415 strcat(buffer, format);
1416
1417 sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t",
1418 protocolData -> replyBitsIn_[i], protocolData -> replyBitsIn_[i] / 8192,
1419 protocolData -> replyBitsOut_[i], protocolData -> replyBitsOut_[i] / 8192,
1420 protocolData -> replyBitsIn_[i] / protocolData -> replyCount_[i],
1421 protocolData -> replyBitsOut_[i] / protocolData -> replyCount_[i]);
1422
1423 strcat(buffer, format);
1424
1425 if (protocolData -> replyBitsOut_[i] > 0)
1426 {
1427 sprintf(format, "%5.3f:1\n", protocolData -> replyBitsIn_[i] /
1428 protocolData -> replyBitsOut_[i]);
1429 }
1430 else
1431 {
1432 sprintf(format, "1:1\n");
1433 }
1434
1435 strcat(buffer, format);
1436 }
1437
1438 countReplyIn += protocolData -> replyCount_[i];
1439 countCachedReplyIn += protocolData -> replyCached_[i];
1440
1441 countReplyBitsIn += protocolData -> replyBitsIn_[i];
1442 countReplyBitsOut += protocolData -> replyBitsOut_[i];
1443
1444 countAnyIn += protocolData -> replyCount_[i];
1445 countBitsIn += protocolData -> replyBitsIn_[i];
1446 countBitsOut += protocolData -> replyBitsOut_[i];
1447 }
1448
1449 if (countReplyIn > 0)
1450 {
1451 if (countCachedReplyIn > 0)
1452 {
1453 sprintf(format, "\ntotal: %.0f\t%.0f", countReplyIn, countCachedReplyIn);
1454 }
1455 else
1456 {
1457 sprintf(format, "\ntotal: %.0f\t", countReplyIn);
1458 }
1459
1460 strcat(buffer, format);
1461
1462 sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t",
1463 countReplyBitsIn, countReplyBitsIn / 8192, countReplyBitsOut,
1464 countReplyBitsOut / 8192, countReplyBitsIn / countReplyIn,
1465 countReplyBitsOut / countReplyIn);
1466
1467 strcat(buffer, format);
1468
1469 if (countReplyBitsOut > 0)
1470 {
1471 sprintf(format, "%5.3f:1\n", countReplyBitsIn / countReplyBitsOut);
1472 }
1473 else
1474 {
1475 sprintf(format, "1:1\n");
1476 }
1477
1478 strcat(buffer, format);
1479 }
1480 else
1481 {
1482 strcat(buffer, "N/A\n");
1483 }
1484
1485 strcat(buffer, "\n");
1486
1487 //
1488 // Print event and error data.
1489 //
1490
1491 strcat(buffer, "Event Total\tCached\tBits In\t\tBits Out\tBits/Event\t\tRatio\n");
1492 strcat(buffer, "------- -----\t------\t-------\t\t--------\t----------\t\t-----\n");
1493
1494 for (int i = 0; i < STATISTICS_OPCODE_MAX; i++)
1495 {
1496 if (protocolData -> eventCount_[i])
1497 {
1498 sprintf(format, "#%d ", i);
1499
1500 while (strlen(format) < 8)
1501 {
1502 strcat(format, " ");
1503 }
1504
1505 strcat(buffer, format);
1506
1507 if (protocolData -> eventCached_[i] > 0)
1508 {
1509 sprintf(format, "%.0f\t%.0f", protocolData -> eventCount_[i],
1510 protocolData -> eventCached_[i]);
1511 }
1512 else
1513 {
1514 sprintf(format, "%.0f\t", protocolData -> eventCount_[i]);
1515 }
1516
1517 strcat(buffer, format);
1518
1519 sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t",
1520 protocolData -> eventBitsIn_[i], protocolData -> eventBitsIn_[i] / 8192,
1521 protocolData -> eventBitsOut_[i], protocolData -> eventBitsOut_[i] / 8192,
1522 protocolData -> eventBitsIn_[i] / protocolData -> eventCount_[i],
1523 protocolData -> eventBitsOut_[i] / protocolData -> eventCount_[i]);
1524
1525 strcat(buffer, format);
1526
1527 if (protocolData -> eventBitsOut_[i] > 0)
1528 {
1529 sprintf(format, "%5.3f:1\n", protocolData -> eventBitsIn_[i] /
1530 protocolData -> eventBitsOut_[i]);
1531 }
1532 else
1533 {
1534 sprintf(format, "1:1\n");
1535 }
1536
1537 strcat(buffer, format);
1538 }
1539
1540 countEventIn += protocolData -> eventCount_[i];
1541 countCachedEventIn += protocolData -> eventCached_[i];
1542
1543 countEventBitsIn += protocolData -> eventBitsIn_[i];
1544 countEventBitsOut += protocolData -> eventBitsOut_[i];
1545
1546 countAnyIn += protocolData -> eventCount_[i];
1547 countBitsIn += protocolData -> eventBitsIn_[i];
1548 countBitsOut += protocolData -> eventBitsOut_[i];
1549 }
1550
1551 if (countEventIn > 0)
1552 {
1553 if (countCachedEventIn > 0)
1554 {
1555 sprintf(format, "\ntotal: %.0f\t%.0f", countEventIn, countCachedEventIn);
1556 }
1557 else
1558 {
1559 sprintf(format, "\ntotal: %.0f\t", countEventIn);
1560 }
1561
1562 strcat(buffer, format);
1563
1564 sprintf(format, "\t%.0f (%.0f KB)\t%.0f (%.0f KB)\t%.0f/1 -> %.0f/1 \t",
1565 countEventBitsIn, countEventBitsIn / 8192, countEventBitsOut,
1566 countEventBitsOut / 8192, countEventBitsIn / countEventIn,
1567 countEventBitsOut / countEventIn);
1568
1569 strcat(buffer, format);
1570
1571 if (countEventBitsOut > 0)
1572 {
1573 sprintf(format, "%5.3f:1\n", countEventBitsIn / countEventBitsOut);
1574 }
1575 else
1576 {
1577 sprintf(format, "1:1\n");
1578 }
1579
1580 strcat(buffer, format);
1581 }
1582 else
1583 {
1584 strcat(buffer, "N/A\n\n");
1585 }
1586
1587 //
1588 // Print transport data.
1589 //
1590
1591 getTimeStats(type, buffer);
1592
1593 countAnyIn += protocolData -> cupsCount_;
1594 countBitsIn += protocolData -> cupsBitsIn_;
1595 countBitsOut += protocolData -> cupsBitsOut_;
1596
1597 countAnyIn += protocolData -> smbCount_;
1598 countBitsIn += protocolData -> smbBitsIn_;
1599 countBitsOut += protocolData -> smbBitsOut_;
1600
1601 countAnyIn += protocolData -> mediaCount_;
1602 countBitsIn += protocolData -> mediaBitsIn_;
1603 countBitsOut += protocolData -> mediaBitsOut_;
1604
1605 countAnyIn += protocolData -> httpCount_;
1606 countBitsIn += protocolData -> httpBitsIn_;
1607 countBitsOut += protocolData -> httpBitsOut_;
1608
1609 countAnyIn += protocolData -> fontCount_;
1610 countBitsIn += protocolData -> fontBitsIn_;
1611 countBitsOut += protocolData -> fontBitsOut_;
1612
1613 countAnyIn += protocolData -> slaveCount_;
1614 countBitsIn += protocolData -> slaveBitsIn_;
1615 countBitsOut += protocolData -> slaveBitsOut_;
1616
1617 //
1618 // Save the overall amount of bytes
1619 // coming from X clients.
1620 //
1621
1622 overallData -> overallBytesIn_ = countBitsIn / 8;
1623
1624 //
1625 // Print performance data.
1626 //
1627
1628 if (transportData -> readTime_ > 0)
1629 {
1630 sprintf(format, " %.0f messages (%.0f KB) encoded per second.\n\n",
1631 countAnyIn / (transportData -> readTime_ / 1000),
1632 (countBitsIn + transportData -> framingBitsOut_) / 8192 /
1633 (transportData -> readTime_ / 1000));
1634 }
1635 else
1636 {
1637 sprintf(format, " %.0f messages (%.0f KB) encoded per second.\n\n",
1638 countAnyIn, (countBitsIn + transportData ->
1639 framingBitsOut_) / 8192);
1640 }
1641
1642 strcat(buffer, format);
1643
1644 strcat(buffer, "link: ");
1645
1646 //
1647 // ZLIB compression stats.
1648 //
1649
1650 getStreamStats(type, buffer);
1651
1652 //
1653 // Save the overall amount of bytes
1654 // sent on NX proxy link.
1655 //
1656
1657 if (transportData -> compressedBytesOut_ > 0)
1658 {
1659 overallData -> overallBytesOut_ = transportData -> compressedBytesOut_;
1660 }
1661 else
1662 {
1663 overallData -> overallBytesOut_ = countBitsOut / 8;
1664 }
1665
1666 //
1667 // Print info on multiplexing overhead.
1668 //
1669
1670 getFramingStats(type, buffer);
1671
1672 //
1673 // Print stats about additional channels.
1674 //
1675
1676 getServicesStats(type, buffer);
1677
1678 //
1679 // Compression summary.
1680 //
1681
1682 double ratio = 1;
1683
1684 if (transportData -> compressedBytesOut_ / 1024 > 0)
1685 {
1686 ratio = ((countBitsIn + transportData -> framingBitsOut_) / 8192) /
1687 (transportData -> compressedBytesOut_ / 1024);
1688
1689 }
1690 else if (countBitsOut > 0)
1691 {
1692 ratio = (countBitsIn + transportData -> framingBitsOut_) /
1693 countBitsOut;
1694 }
1695
1696 sprintf(format, " Protocol compression ratio is %5.3f:1.\n\n",
1697 ratio);
1698
1699 strcat(buffer, format);
1700
1701 getBitrateStats(type, buffer);
1702
1703 //
1704 // These are not included in output.
1705 //
1706 // getSplitStats(type, buffer);
1707 //
1708
1709 strcat(buffer, "\n");
1710
1711 //
1712 // These statistics are not included in output.
1713 // You can check it anyway to get the effective
1714 // amount of bytes produced by unpack procedure.
1715 //
1716 // getClientOverallStats(type, buffer);
1717 //
1718
1719 return 1;
1720 }
1721
getServerOverallStats(int type,char * & buffer)1722 int Statistics::getServerOverallStats(int type, char *&buffer)
1723 {
1724 return 1;
1725 }
1726
getTimeStats(int type,char * & buffer)1727 int Statistics::getTimeStats(int type, char *&buffer)
1728 {
1729 struct T_transportData *transportData;
1730
1731 if (type == PARTIAL_STATS)
1732 {
1733 transportData = &transportPartial_;
1734 }
1735 else
1736 {
1737 transportData = &transportTotal_;
1738 }
1739
1740 char format[FORMAT_LENGTH];
1741
1742 sprintf(format, "\ntime: %.0f Ms idle, %.0f Ms (%.0f Ms in read, %.0f Ms in write) running.\n\n",
1743 transportData -> idleTime_, transportData -> readTime_,
1744 transportData -> readTime_ - transportData -> writeTime_,
1745 transportData -> writeTime_);
1746
1747 strcat(buffer, format);
1748
1749 return 1;
1750 }
1751
getStreamStats(int type,char * & buffer)1752 int Statistics::getStreamStats(int type, char *&buffer)
1753 {
1754 struct T_transportData *transportData;
1755
1756 if (type == PARTIAL_STATS)
1757 {
1758 transportData = &transportPartial_;
1759 }
1760 else
1761 {
1762 transportData = &transportTotal_;
1763 }
1764
1765 char format[FORMAT_LENGTH];
1766
1767 if (transportData -> compressedBytesOut_ > 0)
1768 {
1769 sprintf(format, "%.0f bytes (%.0f KB) compressed to %.0f (%.0f KB).\n",
1770 transportData -> compressedBytesIn_, transportData -> compressedBytesIn_ / 1024,
1771 transportData -> compressedBytesOut_, transportData -> compressedBytesOut_ / 1024);
1772
1773 strcat(buffer, format);
1774
1775 sprintf(format, " %5.3f:1 stream compression ratio.\n\n",
1776 transportData -> compressedBytesIn_ / transportData -> compressedBytesOut_);
1777
1778 strcat(buffer, format);
1779 }
1780
1781 if (transportData -> decompressedBytesOut_ > 0)
1782 {
1783 if (transportData -> compressedBytesOut_ > 0)
1784 {
1785 strcat(buffer, " ");
1786 }
1787
1788 sprintf(format, "%.0f bytes (%.0f KB) decompressed to %.0f (%.0f KB).\n",
1789 transportData -> decompressedBytesIn_, transportData -> decompressedBytesIn_ / 1024,
1790 transportData -> decompressedBytesOut_, transportData -> decompressedBytesOut_ / 1024);
1791
1792 strcat(buffer, format);
1793
1794 sprintf(format, " %5.3f:1 stream compression ratio.\n\n",
1795 transportData -> decompressedBytesOut_ / transportData -> decompressedBytesIn_);
1796
1797 strcat(buffer, format);
1798 }
1799
1800 if (transportData -> compressedBytesOut_ > 0 ||
1801 transportData -> decompressedBytesOut_ > 0)
1802 {
1803 strcat(buffer, " ");
1804 }
1805
1806 return 1;
1807 }
1808
getServicesStats(int type,char * & buffer)1809 int Statistics::getServicesStats(int type, char *&buffer)
1810 {
1811 struct T_protocolData *protocolData;
1812
1813 if (type == PARTIAL_STATS)
1814 {
1815 protocolData = &protocolPartial_;
1816 }
1817 else
1818 {
1819 protocolData = &protocolTotal_;
1820 }
1821
1822 char format[FORMAT_LENGTH];
1823
1824 if (protocolData -> cupsBitsOut_ > 0)
1825 {
1826 sprintf(format, " %.0f CUPS messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n",
1827 protocolData -> cupsCount_ , protocolData -> cupsBitsIn_ / 8,
1828 protocolData -> cupsBitsIn_ / 8192, protocolData -> cupsBitsOut_ / 8,
1829 protocolData -> cupsBitsOut_ / 8192);
1830
1831 strcat(buffer, format);
1832 }
1833
1834 if (protocolData -> smbBitsOut_ > 0)
1835 {
1836 sprintf(format, " %.0f SMB messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n",
1837 protocolData -> smbCount_ , protocolData -> smbBitsIn_ / 8,
1838 protocolData -> smbBitsIn_ / 8192, protocolData -> smbBitsOut_ / 8,
1839 protocolData -> smbBitsOut_ / 8192);
1840
1841 strcat(buffer, format);
1842 }
1843
1844 if (protocolData -> mediaBitsOut_ > 0)
1845 {
1846 sprintf(format, " %.0f multimedia messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n",
1847 protocolData -> mediaCount_ , protocolData -> mediaBitsIn_ / 8,
1848 protocolData -> mediaBitsIn_ / 8192, protocolData -> mediaBitsOut_ / 8,
1849 protocolData -> mediaBitsOut_ / 8192);
1850
1851 strcat(buffer, format);
1852 }
1853
1854 if (protocolData -> httpBitsOut_ > 0)
1855 {
1856 sprintf(format, " %.0f HTTP messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n",
1857 protocolData -> httpCount_ , protocolData -> httpBitsIn_ / 8,
1858 protocolData -> httpBitsIn_ / 8192, protocolData -> httpBitsOut_ / 8,
1859 protocolData -> httpBitsOut_ / 8192);
1860
1861 strcat(buffer, format);
1862 }
1863
1864 if (protocolData -> fontBitsOut_ > 0)
1865 {
1866 sprintf(format, " %.0f font server messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n",
1867 protocolData -> fontCount_ , protocolData -> fontBitsIn_ / 8,
1868 protocolData -> fontBitsIn_ / 8192, protocolData -> fontBitsOut_ / 8,
1869 protocolData -> fontBitsOut_ / 8192);
1870
1871 strcat(buffer, format);
1872 }
1873
1874 if (protocolData -> slaveBitsOut_ > 0)
1875 {
1876 sprintf(format, " %.0f slave messages, %.0f bytes (%.0f KB) in, %.0f bytes (%.0f KB) out.\n\n",
1877 protocolData -> slaveCount_ , protocolData -> slaveBitsIn_ / 8,
1878 protocolData -> slaveBitsIn_ / 8192, protocolData -> slaveBitsOut_ / 8,
1879 protocolData -> slaveBitsOut_ / 8192);
1880
1881 strcat(buffer, format);
1882 }
1883
1884 return 1;
1885 }
1886
getFramingStats(int type,char * & buffer)1887 int Statistics::getFramingStats(int type, char *&buffer)
1888 {
1889 struct T_transportData *transportData;
1890
1891 if (type == PARTIAL_STATS)
1892 {
1893 transportData = &transportPartial_;
1894 }
1895 else
1896 {
1897 transportData = &transportTotal_;
1898 }
1899
1900 char format[FORMAT_LENGTH];
1901
1902 //
1903 // Print info on multiplexing overhead.
1904 //
1905
1906 sprintf(format, "%.0f frames in, %.0f frames out, %.0f writes out.\n\n",
1907 transportData -> proxyFramesIn_, transportData -> proxyFramesOut_,
1908 transportData -> proxyWritesOut_);
1909
1910 strcat(buffer, format);
1911
1912 sprintf(format, " %.0f bytes (%.0f KB) used for framing and multiplexing.\n\n",
1913 transportData -> framingBitsOut_ / 8, transportData -> framingBitsOut_ / 8192);
1914
1915 strcat(buffer, format);
1916
1917 return 1;
1918 }
1919
getBitrateStats(int type,char * & buffer)1920 int Statistics::getBitrateStats(int type, char *&buffer)
1921 {
1922 struct T_transportData *transportData;
1923 struct T_overallData *overallData;
1924
1925 if (type == PARTIAL_STATS)
1926 {
1927 transportData = &transportPartial_;
1928 overallData = &overallPartial_;
1929 }
1930 else
1931 {
1932 transportData = &transportTotal_;
1933 overallData = &overallTotal_;
1934 }
1935
1936 double total = 0;
1937
1938 if (transportData -> idleTime_ + transportData -> readTime_ > 0)
1939 {
1940 total = overallData -> overallBytesOut_ /
1941 ((transportData -> idleTime_ + transportData -> readTime_) / 1000);
1942 }
1943
1944 char format[FORMAT_LENGTH];
1945
1946 sprintf(format, " %.0f B/s average, %d B/s %ds, %d B/s %ds, %d B/s maximum.\n\n",
1947 total, getBitrateInShortFrame(), control -> ShortBitrateTimeFrame / 1000,
1948 getBitrateInLongFrame(), control -> LongBitrateTimeFrame / 1000,
1949 getTopBitrate());
1950
1951 strcat(buffer, format);
1952
1953 resetTopBitrate();
1954
1955 return 1;
1956 }
1957
getSplitStats(int type,char * & buffer)1958 int Statistics::getSplitStats(int type, char *&buffer)
1959 {
1960 //
1961 // Don't print these statistics if persistent
1962 // cache of images is disabled.
1963 //
1964
1965 if (control -> ImageCacheEnableLoad == 0 &&
1966 control -> ImageCacheEnableSave == 0)
1967 {
1968 return 0;
1969 }
1970
1971 struct T_splitData *splitData;
1972
1973 if (type == PARTIAL_STATS)
1974 {
1975 splitData = &splitPartial_;
1976 }
1977 else
1978 {
1979 splitData = &splitTotal_;
1980 }
1981
1982 char format[FORMAT_LENGTH];
1983
1984 //
1985 // Print info on split messages restored from disk.
1986 //
1987
1988 sprintf(format, " %.0f images streamed, %.0f restored, %.0f bytes (%.0f KB) cached.\n\n",
1989 splitData -> splitCount_, splitData -> splitAborted_, splitData -> splitAbortedBytesOut_,
1990 splitData -> splitAbortedBytesOut_ / 1024);
1991
1992 strcat(buffer, format);
1993
1994 return 1;
1995 }
1996