aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/ccids/lib/tfrc_equation.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2006-12-03 22:24:40 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-12-03 22:24:40 -0500
commit83ac58ba0a26228c0b16baa2c4b821de9c4ad5ca (patch)
tree6c8354a6314c39c5fa3f923e4095c16a5fed3d08 /net/dccp/ccids/lib/tfrc_equation.c
parentb4ad86bf52469b26148c677cb59d8bc81f129cc2 (diff)
parent2bbf29acd8f7adcf161de7e5d891b4095687a59f (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/acme/net-2.6
Diffstat (limited to 'net/dccp/ccids/lib/tfrc_equation.c')
-rw-r--r--net/dccp/ccids/lib/tfrc_equation.c222
1 files changed, 139 insertions, 83 deletions
diff --git a/net/dccp/ccids/lib/tfrc_equation.c b/net/dccp/ccids/lib/tfrc_equation.c
index 2601012383fb..ddac2c511e2f 100644
--- a/net/dccp/ccids/lib/tfrc_equation.c
+++ b/net/dccp/ccids/lib/tfrc_equation.c
@@ -18,10 +18,79 @@
18#include "tfrc.h" 18#include "tfrc.h"
19 19
20#define TFRC_CALC_X_ARRSIZE 500 20#define TFRC_CALC_X_ARRSIZE 500
21#define TFRC_CALC_X_SPLIT 50000 /* 0.05 * 1000000, details below */
22#define TFRC_SMALLEST_P (TFRC_CALC_X_SPLIT/TFRC_CALC_X_ARRSIZE)
21 23
22#define TFRC_CALC_X_SPLIT 50000 24/*
23/* equivalent to 0.05 */ 25 TFRC TCP Reno Throughput Equation Lookup Table for f(p)
24 26
27 The following two-column lookup table implements a part of the TCP throughput
28 equation from [RFC 3448, sec. 3.1]:
29
30 s
31 X_calc = --------------------------------------------------------------
32 R * sqrt(2*b*p/3) + (3 * t_RTO * sqrt(3*b*p/8) * (p + 32*p^3))
33
34 Where:
35 X is the transmit rate in bytes/second
36 s is the packet size in bytes
37 R is the round trip time in seconds
38 p is the loss event rate, between 0 and 1.0, of the number of loss
39 events as a fraction of the number of packets transmitted
40 t_RTO is the TCP retransmission timeout value in seconds
41 b is the number of packets acknowledged by a single TCP ACK
42
43 We can assume that b = 1 and t_RTO is 4 * R. The equation now becomes:
44
45 s
46 X_calc = -------------------------------------------------------
47 R * sqrt(p*2/3) + (12 * R * sqrt(p*3/8) * (p + 32*p^3))
48
49 which we can break down into:
50
51 s
52 X_calc = ---------
53 R * f(p)
54
55 where f(p) is given for 0 < p <= 1 by:
56
57 f(p) = sqrt(2*p/3) + 12 * sqrt(3*p/8) * (p + 32*p^3)
58
59 Since this is kernel code, floating-point arithmetic is avoided in favour of
60 integer arithmetic. This means that nearly all fractional parameters are
61 scaled by 1000000:
62 * the parameters p and R
63 * the return result f(p)
64 The lookup table therefore actually tabulates the following function g(q):
65
66 g(q) = 1000000 * f(q/1000000)
67
68 Hence, when p <= 1, q must be less than or equal to 1000000. To achieve finer
69 granularity for the practically more relevant case of small values of p (up to
70 5%), the second column is used; the first one ranges up to 100%. This split
71 corresponds to the value of q = TFRC_CALC_X_SPLIT. At the same time this also
72 determines the smallest resolution possible with this lookup table:
73
74 TFRC_SMALLEST_P = TFRC_CALC_X_SPLIT / TFRC_CALC_X_ARRSIZE
75
76 The entire table is generated by:
77 for(i=0; i < TFRC_CALC_X_ARRSIZE; i++) {
78 lookup[i][0] = g((i+1) * 1000000/TFRC_CALC_X_ARRSIZE);
79 lookup[i][1] = g((i+1) * TFRC_CALC_X_SPLIT/TFRC_CALC_X_ARRSIZE);
80 }
81
82 With the given configuration, we have, with M = TFRC_CALC_X_ARRSIZE-1,
83 lookup[0][0] = g(1000000/(M+1)) = 1000000 * f(0.2%)
84 lookup[M][0] = g(1000000) = 1000000 * f(100%)
85 lookup[0][1] = g(TFRC_SMALLEST_P) = 1000000 * f(0.01%)
86 lookup[M][1] = g(TFRC_CALC_X_SPLIT) = 1000000 * f(5%)
87
88 In summary, the two columns represent f(p) for the following ranges:
89 * The first column is for 0.002 <= p <= 1.0
90 * The second column is for 0.0001 <= p <= 0.05
91 Where the columns overlap, the second (finer-grained) is given preference,
92 i.e. the first column is used only for p >= 0.05.
93 */
25static const u32 tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE][2] = { 94static const u32 tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE][2] = {
26 { 37172, 8172 }, 95 { 37172, 8172 },
27 { 53499, 11567 }, 96 { 53499, 11567 },
@@ -525,85 +594,69 @@ static const u32 tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE][2] = {
525 { 243315981, 271305 } 594 { 243315981, 271305 }
526}; 595};
527 596
528/* Calculate the send rate as per section 3.1 of RFC3448 597/* return largest index i such that fval <= lookup[i][small] */
529 598static inline u32 tfrc_binsearch(u32 fval, u8 small)
530Returns send rate in bytes per second 599{
531 600 u32 try, low = 0, high = TFRC_CALC_X_ARRSIZE - 1;
532Integer maths and lookups are used as not allowed floating point in kernel 601
533 602 while (low < high) {
534The function for Xcalc as per section 3.1 of RFC3448 is: 603 try = (low + high) / 2;
535 604 if (fval <= tfrc_calc_x_lookup[try][small])
536X = s 605 high = try;
537 ------------------------------------------------------------- 606 else
538 R*sqrt(2*b*p/3) + (t_RTO * (3*sqrt(3*b*p/8) * p * (1+32*p^2))) 607 low = try + 1;
539 608 }
540where 609 return high;
541X is the trasmit rate in bytes/second 610}
542s is the packet size in bytes
543R is the round trip time in seconds
544p is the loss event rate, between 0 and 1.0, of the number of loss events
545 as a fraction of the number of packets transmitted
546t_RTO is the TCP retransmission timeout value in seconds
547b is the number of packets acknowledged by a single TCP acknowledgement
548
549we can assume that b = 1 and t_RTO is 4 * R. With this the equation becomes:
550
551X = s
552 -----------------------------------------------------------------------
553 R * sqrt(2 * p / 3) + (12 * R * (sqrt(3 * p / 8) * p * (1 + 32 * p^2)))
554
555
556which we can break down into:
557
558X = s
559 --------
560 R * f(p)
561
562where f(p) = sqrt(2 * p / 3) + (12 * sqrt(3 * p / 8) * p * (1 + 32 * p * p))
563
564Function parameters:
565s - bytes
566R - RTT in usecs
567p - loss rate (decimal fraction multiplied by 1,000,000)
568
569Returns Xcalc in bytes per second
570
571DON'T alter this code unless you run test cases against it as the code
572has been manipulated to stop underflow/overlow.
573 611
574*/ 612/**
613 * tfrc_calc_x - Calculate the send rate as per section 3.1 of RFC3448
614 *
615 * @s: packet size in bytes
616 * @R: RTT scaled by 1000000 (i.e., microseconds)
617 * @p: loss ratio estimate scaled by 1000000
618 * Returns X_calc in bytes per second (not scaled).
619 *
620 * Note: DO NOT alter this code unless you run test cases against it,
621 * as the code has been optimized to stop underflow/overflow.
622 */
575u32 tfrc_calc_x(u16 s, u32 R, u32 p) 623u32 tfrc_calc_x(u16 s, u32 R, u32 p)
576{ 624{
577 int index; 625 int index;
578 u32 f; 626 u32 f;
579 u64 tmp1, tmp2; 627 u64 tmp1, tmp2;
580 628
581 if (p < TFRC_CALC_X_SPLIT) 629 /* check against invalid parameters and divide-by-zero */
582 index = (p / (TFRC_CALC_X_SPLIT / TFRC_CALC_X_ARRSIZE)) - 1; 630 BUG_ON(p > 1000000); /* p must not exceed 100% */
583 else 631 BUG_ON(p == 0); /* f(0) = 0, divide by zero */
584 index = (p / (1000000 / TFRC_CALC_X_ARRSIZE)) - 1; 632 if (R == 0) { /* possible divide by zero */
633 DCCP_CRIT("WARNING: RTT is 0, returning maximum X_calc.");
634 return ~0U;
635 }
585 636
586 if (index < 0) 637 if (p <= TFRC_CALC_X_SPLIT) { /* 0.0000 < p <= 0.05 */
587 /* p should be 0 unless there is a bug in my code */ 638 if (p < TFRC_SMALLEST_P) { /* 0.0000 < p < 0.0001 */
588 index = 0; 639 DCCP_WARN("Value of p (%d) below resolution. "
640 "Substituting %d\n", p, TFRC_SMALLEST_P);
641 index = 0;
642 } else /* 0.0001 <= p <= 0.05 */
643 index = p/TFRC_SMALLEST_P - 1;
589 644
590 if (R == 0) { 645 f = tfrc_calc_x_lookup[index][1];
591 DCCP_WARN("RTT==0, setting to 1\n");
592 R = 1; /* RTT can't be zero or else divide by zero */
593 }
594 646
595 BUG_ON(index >= TFRC_CALC_X_ARRSIZE); 647 } else { /* 0.05 < p <= 1.00 */
648 index = p/(1000000/TFRC_CALC_X_ARRSIZE) - 1;
596 649
597 if (p >= TFRC_CALC_X_SPLIT)
598 f = tfrc_calc_x_lookup[index][0]; 650 f = tfrc_calc_x_lookup[index][0];
599 else 651 }
600 f = tfrc_calc_x_lookup[index][1];
601 652
653 /* The following computes X = s/(R*f(p)) in bytes per second. Since f(p)
654 * and R are both scaled by 1000000, we need to multiply by 1000000^2.
655 * ==> DO NOT alter this unless you test against overflow on 32 bit */
602 tmp1 = ((u64)s * 100000000); 656 tmp1 = ((u64)s * 100000000);
603 tmp2 = ((u64)R * (u64)f); 657 tmp2 = ((u64)R * (u64)f);
604 do_div(tmp2, 10000); 658 do_div(tmp2, 10000);
605 do_div(tmp1, tmp2); 659 do_div(tmp1, tmp2);
606 /* Don't alter above math unless you test due to overflow on 32 bit */
607 660
608 return (u32)tmp1; 661 return (u32)tmp1;
609} 662}
@@ -611,33 +664,36 @@ u32 tfrc_calc_x(u16 s, u32 R, u32 p)
611EXPORT_SYMBOL_GPL(tfrc_calc_x); 664EXPORT_SYMBOL_GPL(tfrc_calc_x);
612 665
613/* 666/*
614 * args: fvalue - function value to match 667 * tfrc_calc_x_reverse_lookup - try to find p given f(p)
615 * returns: p closest to that value
616 * 668 *
617 * both fvalue and p are multiplied by 1,000,000 to use ints 669 * @fvalue: function value to match, scaled by 1000000
670 * Returns closest match for p, also scaled by 1000000
618 */ 671 */
619u32 tfrc_calc_x_reverse_lookup(u32 fvalue) 672u32 tfrc_calc_x_reverse_lookup(u32 fvalue)
620{ 673{
621 int ctr = 0; 674 int index;
622 int small;
623 675
624 if (fvalue < tfrc_calc_x_lookup[0][1]) 676 if (fvalue == 0) /* f(p) = 0 whenever p = 0 */
625 return 0; 677 return 0;
626 678
627 if (fvalue <= tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][1]) 679 /* Error cases. */
628 small = 1; 680 if (fvalue < tfrc_calc_x_lookup[0][1]) {
629 else if (fvalue > tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][0]) 681 DCCP_WARN("fvalue %d smaller than resolution\n", fvalue);
682 return tfrc_calc_x_lookup[0][1];
683 }
684 if (fvalue > tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][0]) {
685 DCCP_WARN("fvalue %d exceeds bounds!\n", fvalue);
630 return 1000000; 686 return 1000000;
631 else 687 }
632 small = 0;
633
634 while (fvalue > tfrc_calc_x_lookup[ctr][small])
635 ctr++;
636 688
637 if (small) 689 if (fvalue <= tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][1]) {
638 return TFRC_CALC_X_SPLIT * ctr / TFRC_CALC_X_ARRSIZE; 690 index = tfrc_binsearch(fvalue, 1);
639 else 691 return (index + 1) * TFRC_CALC_X_SPLIT / TFRC_CALC_X_ARRSIZE;
640 return 1000000 * ctr / TFRC_CALC_X_ARRSIZE; 692 }
693
694 /* else ... it must be in the coarse-grained column */
695 index = tfrc_binsearch(fvalue, 0);
696 return (index + 1) * 1000000 / TFRC_CALC_X_ARRSIZE;
641} 697}
642 698
643EXPORT_SYMBOL_GPL(tfrc_calc_x_reverse_lookup); 699EXPORT_SYMBOL_GPL(tfrc_calc_x_reverse_lookup);