Re: [PATCH] [RFC]: Fine-grained sending rate resolution / division errors

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Quoting Arnaldo Carvalho de Melo:
o:
|  > |  > Here is now the patch, I have had a hard time due to division of u64 by
|  > |  > u32. I have also checked again - it is feasible to prune X_calc and
|  > |  > X_recv back to u32. If you prefer that, I can change the patch.
|  > |
|  > |  If it is possible, its better, minus 8 bytes per half connection
|  > I have checked again - the best that seems possible is 4 bytes less. This
|  > is due to X_recv which acts as cache in [RFC 3448, 4.4] - lots of division
|  > operations where the value needs to be stored afterwards again.
|  > So X_calc would remain as 32bit, I will write up how I think it should look
|  > like and revise the patch - tomorrow, since the bug hunting took some time
|  > away.
|  
|  OK, take your time.

Please find attached, below, the revised plan for finer-grained resolution; I am using
' << 6' for all scaling operations, for consistency. Patch to codify this follows later.


	Revised approach to achieve finer-grained resolution of sending rates
	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	I) Summary
	----------
	The sending rate X and the cached value X_recv of the receiver-estimated
	sending rate are both scaled by 64 (2^6) in order to: 
		* cope with low sending	rates (minimally 1 byte/second)
		* allow upgrading to a packets-per-second sending principle
		* avoid calculation errors due to integer arithmetic
	The following data types are used:
		* u32 X_calc  -  is maintained in      bytes/second
		* u64 X		  -  is maintained in 64 * bytes/second	
		* u64 X_recv  -  is maintained in 64 * bytes/second	
	This choice is a compromise between minimising the size of sender
	data structures and requirements. X needs to be u64 to avoid overflow,
	X_recv needs a finer granularity to avoid underflow when modifying the
	cached value via the nofeedback timer [RFC 3448, 4.4].
	
	Furthermore, the usecs_div() function should be replaced by:
		* u64 scaled_div(u64 a, u32 b)   -- where u64 is safe 
		* u32 scaled_div32(u64 a, u32 b) -- which tests against overflow


	II) Initialisation [RFC 3448, 4.2]
	----------------------------------
	Set X[/s] to 64 * 1 packet / second 	(i.e.,  X  =  s << 6)
	
	
	III) Sender behaviour when a feedback packet is received
	--------------------------------------------------------
	(a) Scale X_recv when it is received:
	 
	     X_recv  =  hctx->packet_options_x_recv << 6
	
	(b) Step (4) of  [RFC 3448, 4.3]:
		
		If (p > 0) {

          		X_calc = calcX(s, R, p)	
            
          	        X  =  min(X_calc << 6, 2 * X_recv)   	/* X_recv is already scaled */
  			X  =  max(X, (s << 6)/t_mbi)

  		} Else If(t_now - tld >= R) {
  		
  			X  =  2 * min(X, X_recv)
  			X  =  max(X, scaled_div(s << 6, R))	/*  R in microseconds */
		
			tld = t_now
  		}
  		
  	(c) Step (5) of  [RFC 3448, 4.3]: 
  		The nofeedback timer is set to expire in 
  		t_nfb =	max(4 * R, scaled_div32(2 * s, X >> 6)) 
  			
  			
	IV) Expiration of the nofeedback timer [RFC 3448, 4.4]
	------------------------------------------------------
	(a) If the sender has previously received feedback from the receiver
		
		If (p == 0 ||  
		    X_calc > (X_recv >> 5))   		/* divided by 2^6, multiplied by 2^1 */
		
			X_recv  =  max(X_recv/2, (s << 6)/(2*t_mbi))

		Else
				
			X_recv  =  X_calc << 4		/* scaled by 2^6, divided by 2^2 */
			
	
		/* recalculate X according to [RFC 3448, 4.3]   */
		
		/* expire the nofeedback timer after: */
		t_nfb = max(4 * R, scaled_div32(2 * s, X >> 6))
					  
					  
	(b) If the sender does not yet have feedback
	
		X  =  max(X/2, (s << 6)/t_mbi)
		
		/* set the nofeedback timer to expire after 2 seconds */

					  

	V) Scheduling of Packet Transmissions [RFC 3448, 4.6]
	-----------------------------------------------------
	        
	        t_ipi   =   scaled_div(s, X >> 6)           /* microseconds */
      
	VI) Larger initial windows [RFC 4342, sec. 5]
	---------------------------------------------
            w_init  =  min(4*s , max(2*s, 4380))
            X       =  scaled_div(w_init << 6, R)
            

	VII) Overflow analysis of scaled_div/scaled_div32
	-------------------------------------------------
	The way the functions are used as above is safe, since:
	
	IIIb):  X  =  max(X, scaled_div(s << 6, R))
	        Is safe since (2^32 - 1)*64*1E6 fit in u64
	        
	IIIc):  t_nfb = max(4 * R, scaled_div32(2 * s, X >> 6))
			This can overflow (e.g. s=(2^32 -1) and X>>6 = 1),
			hence we need the overflow test of scaled_div32
			
	IVa):   analogous to IIIc
	
	V):     t_ipi = scaled_div(s, X >> 6)
			This is safe on u32, since s <= 2^32 -1 and X > 0
			Hence we do not need scaled_div32() here
			
	VI):    X  =  scaled_div(w_init << 6, R)
			This is safe, since 4380*64*1E6 fit in u64 (worst case with
			R=1 and w_init=4380) 
		
	
	VIII) Further simplification
	----------------------------
	Since the constant t_mbi = 64 is a power of two, the following
	simplifications are additionally possible:
		* (s << 6)/t_mbi      can be replaced with s
		* (s << 6)/(2*t_mbi)  can be replaced with s/2
-
To unsubscribe from this list: send the line "unsubscribe dccp" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel]     [IETF DCCP]     [Linux Networking]     [Git]     [Security]     [Linux Assembly]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux