Просмотр исходного кода

Merge pull request #403 from rod-hynes/master

Tweak limited memory mode
Rod Hynes 8 лет назад
Родитель
Сommit
c7a4d1dd5f

+ 1 - 1
MobileLibrary/iOS/PsiphonTunnel/PsiphonTunnel/PsiphonTunnel.m

@@ -793,7 +793,7 @@
     // Free getifaddrs data
     // Free getifaddrs data
     freeifaddrs(interfaces);
     freeifaddrs(interfaces);
     
     
-    [self logMessage:[NSString stringWithFormat:@"getActiveInterace: List of UP interfaces: %@", upIffList]];
+    [self logMessage:[NSString stringWithFormat:@"getActiveInterface: List of UP interfaces: %@", upIffList]];
     
     
     // TODO: following is a heuristic for choosing active network interface
     // TODO: following is a heuristic for choosing active network interface
     // Only Wi-Fi and Cellular interfaces are considered
     // Only Wi-Fi and Cellular interfaces are considered

+ 10 - 0
psiphon/config.go

@@ -480,6 +480,16 @@ type Config struct {
 	// memory usage, and selective aggressively garbage collection at high memory
 	// memory usage, and selective aggressively garbage collection at high memory
 	// pressure phases of operation.
 	// pressure phases of operation.
 	LimitedMemoryEnvironment bool
 	LimitedMemoryEnvironment bool
+
+	// LimitedMemoryThreshold limits costly operations when the total memory
+	// allocation exceeds the specified value. This includes limiting the number
+	// of concurrent connection workers to 1.
+	// This option is enabled when LimitedMemoryEnvironment is true and when
+	// LimitedMemoryThreshold > 0.
+	LimitedMemoryThreshold int
+
+	// IgnoreHandshakeStatsRegexps skips compiling and using stats regexes.
+	IgnoreHandshakeStatsRegexps bool
 }
 }
 
 
 // DownloadURL specifies a URL for downloading resources along with parameters
 // DownloadURL specifies a URL for downloading resources along with parameters

+ 24 - 2
psiphon/controller.go

@@ -1025,9 +1025,31 @@ func (controller *Controller) startEstablishing() {
 	controller.peakConcurrentEstablishTunnels = 0
 	controller.peakConcurrentEstablishTunnels = 0
 	controller.concurrentEstablishTunnelsMutex.Unlock()
 	controller.concurrentEstablishTunnelsMutex.Unlock()
 
 
+	workerCount := controller.config.ConnectionWorkerPoolSize
+
 	if controller.config.LimitedMemoryEnvironment {
 	if controller.config.LimitedMemoryEnvironment {
 		setAggressiveGarbageCollection()
 		setAggressiveGarbageCollection()
-		emitMemoryMetrics()
+		totalMemory := emitMemoryMetrics()
+
+		// When total memory size exceeds the threshold, minimize
+		// the number of concurrent connection workers.
+		//
+		// Limitations:
+		// - totalMemory is, at this time, runtime.MemStats.Sys,
+		//   which is virtual memory, not RSS; and which may not
+		//   shrink; so this trigger could be premature and
+		//   permanent.
+		// - Only 1 concurrent worker means a candidate that is
+		//   slow to fail will severely delay the establishment;
+		//   and that it may take significant time to cycle through
+		//   all protocols to find one that works when network
+		//   conditions change.
+
+		if controller.config.LimitedMemoryThreshold > 0 &&
+			totalMemory >= uint64(controller.config.LimitedMemoryThreshold) {
+
+			workerCount = 1
+		}
 	}
 	}
 
 
 	controller.isEstablishing = true
 	controller.isEstablishing = true
@@ -1063,7 +1085,7 @@ func (controller *Controller) startEstablishing() {
 	// TODO: should not favor the first server in this case
 	// TODO: should not favor the first server in this case
 	controller.serverAffinityDoneBroadcast = make(chan struct{})
 	controller.serverAffinityDoneBroadcast = make(chan struct{})
 
 
-	for i := 0; i < controller.config.ConnectionWorkerPoolSize; i++ {
+	for i := 0; i < workerCount; i++ {
 		controller.establishWaitGroup.Add(1)
 		controller.establishWaitGroup.Add(1)
 		go controller.establishTunnelWorker()
 		go controller.establishTunnelWorker()
 	}
 	}

+ 14 - 9
psiphon/serverApi.go

@@ -83,7 +83,8 @@ func MakeSessionId() (sessionId string, err error) {
 // NewServerContext makes the tunnelled handshake request to the Psiphon server
 // NewServerContext makes the tunnelled handshake request to the Psiphon server
 // and returns a ServerContext struct for use with subsequent Psiphon server API
 // and returns a ServerContext struct for use with subsequent Psiphon server API
 // requests (e.g., periodic connected and status requests).
 // requests (e.g., periodic connected and status requests).
-func NewServerContext(tunnel *Tunnel, sessionId string) (*ServerContext, error) {
+func NewServerContext(
+	tunnel *Tunnel, sessionId string, ignoreStatsRegexps bool) (*ServerContext, error) {
 
 
 	// For legacy servers, set up psiphonHttpsClient for
 	// For legacy servers, set up psiphonHttpsClient for
 	// accessing the Psiphon API via the web service.
 	// accessing the Psiphon API via the web service.
@@ -105,7 +106,7 @@ func NewServerContext(tunnel *Tunnel, sessionId string) (*ServerContext, error)
 		psiphonHttpsClient: psiphonHttpsClient,
 		psiphonHttpsClient: psiphonHttpsClient,
 	}
 	}
 
 
-	err := serverContext.doHandshakeRequest()
+	err := serverContext.doHandshakeRequest(ignoreStatsRegexps)
 	if err != nil {
 	if err != nil {
 		return nil, common.ContextError(err)
 		return nil, common.ContextError(err)
 	}
 	}
@@ -116,7 +117,8 @@ func NewServerContext(tunnel *Tunnel, sessionId string) (*ServerContext, error)
 // doHandshakeRequest performs the "handshake" API request. The handshake
 // doHandshakeRequest performs the "handshake" API request. The handshake
 // returns upgrade info, newly discovered server entries -- which are
 // returns upgrade info, newly discovered server entries -- which are
 // stored -- and sponsor info (home pages, stat regexes).
 // stored -- and sponsor info (home pages, stat regexes).
-func (serverContext *ServerContext) doHandshakeRequest() error {
+func (serverContext *ServerContext) doHandshakeRequest(
+	ignoreStatsRegexps bool) error {
 
 
 	params := serverContext.getBaseParams()
 	params := serverContext.getBaseParams()
 
 
@@ -229,13 +231,16 @@ func (serverContext *ServerContext) doHandshakeRequest() error {
 		NoticeClientIsLatestVersion("")
 		NoticeClientIsLatestVersion("")
 	}
 	}
 
 
-	var regexpsNotices []string
-	serverContext.statsRegexps, regexpsNotices = transferstats.MakeRegexps(
-		handshakeResponse.PageViewRegexes,
-		handshakeResponse.HttpsRequestRegexes)
+	if !ignoreStatsRegexps {
 
 
-	for _, notice := range regexpsNotices {
-		NoticeAlert(notice)
+		var regexpsNotices []string
+		serverContext.statsRegexps, regexpsNotices = transferstats.MakeRegexps(
+			handshakeResponse.PageViewRegexes,
+			handshakeResponse.HttpsRequestRegexes)
+
+		for _, notice := range regexpsNotices {
+			NoticeAlert(notice)
+		}
 	}
 	}
 
 
 	serverContext.serverHandshakeTimestamp = handshakeResponse.ServerTimestamp
 	serverContext.serverHandshakeTimestamp = handshakeResponse.ServerTimestamp

+ 2 - 1
psiphon/tunnel.go

@@ -179,7 +179,8 @@ func EstablishTunnel(
 	// fails.
 	// fails.
 	if !config.DisableApi {
 	if !config.DisableApi {
 		NoticeInfo("starting server context for %s", tunnel.serverEntry.IpAddress)
 		NoticeInfo("starting server context for %s", tunnel.serverEntry.IpAddress)
-		tunnel.serverContext, err = NewServerContext(tunnel, sessionId)
+		tunnel.serverContext, err = NewServerContext(
+			tunnel, sessionId, config.IgnoreHandshakeStatsRegexps)
 		if err != nil {
 		if err != nil {
 			return nil, common.ContextError(
 			return nil, common.ContextError(
 				fmt.Errorf("error starting server context for %s: %s",
 				fmt.Errorf("error starting server context for %s: %s",

+ 3 - 2
psiphon/utils.go

@@ -200,7 +200,7 @@ func byteCountFormatter(bytes uint64) string {
 		"%.1f%c", float64(bytes)/math.Pow(float64(base), float64(exp)), "KMGTPEZ"[exp-1])
 		"%.1f%c", float64(bytes)/math.Pow(float64(base), float64(exp)), "KMGTPEZ"[exp-1])
 }
 }
 
 
-func emitMemoryMetrics() {
+func emitMemoryMetrics() uint64 {
 	var memStats runtime.MemStats
 	var memStats runtime.MemStats
 	runtime.ReadMemStats(&memStats)
 	runtime.ReadMemStats(&memStats)
 	NoticeInfo("Memory metrics at %s: goroutines %d | total alloc %s | sys %s | heap alloc/sys/idle/inuse/released/objects %s/%s/%s/%s/%s/%d | stack inuse/sys %s/%s | mspan inuse/sys %s/%s | mcached inuse/sys %s/%s | buckhash/gc/other sys %s/%s/%s | nextgc %s",
 	NoticeInfo("Memory metrics at %s: goroutines %d | total alloc %s | sys %s | heap alloc/sys/idle/inuse/released/objects %s/%s/%s/%s/%s/%d | stack inuse/sys %s/%s | mspan inuse/sys %s/%s | mcached inuse/sys %s/%s | buckhash/gc/other sys %s/%s/%s | nextgc %s",
@@ -224,10 +224,11 @@ func emitMemoryMetrics() {
 		byteCountFormatter(memStats.GCSys),
 		byteCountFormatter(memStats.GCSys),
 		byteCountFormatter(memStats.OtherSys),
 		byteCountFormatter(memStats.OtherSys),
 		byteCountFormatter(memStats.NextGC))
 		byteCountFormatter(memStats.NextGC))
+	return memStats.Sys
 }
 }
 
 
 func setAggressiveGarbageCollection() {
 func setAggressiveGarbageCollection() {
-	debug.SetGCPercent(20)
+	debug.SetGCPercent(5)
 	debug.FreeOSMemory()
 	debug.FreeOSMemory()
 }
 }