Example #1
0
func TestActiveClose(t *testing.T) {
	go func() {
		log.Println(http.ListenAndServe("localhost:6060", nil))
	}()
	s := New()
	s.RegCb(&testcb{s})

	p := make([]runtime.StackRecord, 100)
	fn, _ := runtime.GoroutineProfile(p)
	Println(p[:fn])
	Println("runtime.NumGoroutine()", runtime.NumGoroutine())

	connid, err := s.ConnectBlock("10.1.9.34:9889", time.Second*10)
	if err != nil {
		return
	}
	time.Sleep(time.Second * 50)
	fn, _ = runtime.GoroutineProfile(p)
	Println(p[:fn])
	Println("runtime.NumGoroutine()", runtime.NumGoroutine())

	s.CloseConn(connid)

	time.Sleep(time.Second * 50)
	fn, _ = runtime.GoroutineProfile(p)
	Println(p[:fn])
	Println("runtime.NumGoroutine()", runtime.NumGoroutine())
}
Example #2
0
// NewStackTrace is a constructor function which queries the Go runtime
// for goroutine information and builds a StackTrace object for each.
// A slice of StackTraces, one for each running goroutine, is returned.
func NewStackTrace() []*StackTrace {
	stackRecords := make([]runtime.StackRecord, STACK_BUFFERS)
	count, ok := runtime.GoroutineProfile(stackRecords)
	if !ok {
		return nil
	}

	results := make([]*StackTrace, 0)

	for i := 0; i < count; i++ {
		st := new(StackTrace)
		st.Id = i
		st.Frames = make([]*StackFrame, 0)
		frames := stackRecords[i].Stack()

		for x := range frames {
			f := runtime.FuncForPC(frames[x])
			file, line := f.FileLine(frames[x])
			sf := new(StackFrame)
			sf.Name = strings.TrimSpace(filepath.Base(f.Name()))
			sf.File = strings.TrimSpace(file)
			sf.Line = line

			st.Frames = append(st.Frames, sf)
		}

		results = append(results, st)
	}

	return results
}
Example #3
0
func TestTimeoutAndMemory(t *testing.T) {
	dir := "." + string(os.PathSeparator) + "testin"
	files, err := ioutil.ReadDir(dir)
	if err != nil {
		t.Fatal(err)
	}
	testHTML := make([]string, 0, len(files))
	names := make([]string, 0, len(files))

	for _, file := range files {
		fn := file.Name()
		if strings.HasSuffix(fn, ".html") {
			ffn := dir + string(os.PathSeparator) + fn
			dat, err := ioutil.ReadFile(ffn)
			if err != nil {
				t.Fatal(err)
			}
			testHTML = append(testHTML, string(dat))
			names = append(names, fn)
		}
	}

	fmt.Println("NOTE: this test may take a few minutes to run")

	var ms runtime.MemStats
	var alloc1 uint64
	goroutineCount1 := 2 // the number of goroutines in a quiet state, more if test flags are used
	for i := 0; i < 2; i++ {
		testToMem(testHTML, names, t)
		limit := 60
		var goroutineCount, secs int
		for secs = 1; secs <= limit; secs++ {
			time.Sleep(time.Second) // wait for the timeout goroutines to finish
			goroutineCount, _ = runtime.GoroutineProfile(nil)
			if goroutineCount == goroutineCount1 {
				goto correctGoroutines
			}
		}
		t.Error(fmt.Sprintln("after ", secs, "seconds, num goroutines", goroutineCount, "when should be", goroutineCount1))
	correctGoroutines:
		runtime.GC()
		runtime.ReadMemStats(&ms)
		if alloc1 == 0 {
			alloc1 = ms.Alloc // this is set here to allow for static data set-up by 1st pass through
			fmt.Println("NOTE: base case established in", secs, "seconds. Memory used=", alloc1)
		} else {
			increase := (100.0 * float64(ms.Alloc) / float64(alloc1)) - 100.0
			if increase > 0.2 { // %
				t.Error(fmt.Sprintln("run", i, "memory usage changed from", alloc1, "to", ms.Alloc, "increase:", ms.Alloc-alloc1, "which is", increase, "%"))
			}
		}
	}
}
Example #4
0
func FprintGoroutines(w io.Writer, allFrame bool) {
	ng := runtime.NumGoroutine()
	p := make([]runtime.StackRecord, ng)
	n, ok := runtime.GoroutineProfile(p)
	if !ok {
		panic("The slice is too small too put all records")
		return
	}
	for i := 0; i < n; i++ {
		printStackRecord(w, i, p[i].Stack(), allFrame)
	}
}
Example #5
0
func main() {
	runtime.GOMAXPROCS(200)
	for i := 0; i < 10; i++ {
		go func() {
			for {
				syscall.Close(-1)
			}
		}()
	}
	stk := make([]runtime.StackRecord, 1000)
	for n := 0; ; n++ {
		_, ok := runtime.GoroutineProfile(stk)
		if !ok {
			panic("GoroutineProfile refused")
		}
		if n&(n-1) == 0 {
			println(n)
		}
	}
}
Example #6
0
func TestGoroutineProfile(t *testing.T) {
	// GoroutineProfile used to use the wrong starting sp for
	// goroutines coming out of system calls, causing possible
	// crashes.
	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(100))

	var stop uint32
	defer atomic.StoreUint32(&stop, 1) // in case of panic

	var wg sync.WaitGroup
	for i := 0; i < 4; i++ {
		wg.Add(1)
		go func() {
			for atomic.LoadUint32(&stop) == 0 {
				syscall.Close(-1)
			}
			wg.Done()
		}()
	}

	max := 10000
	if testing.Short() {
		max = 100
	}
	stk := make([]runtime.StackRecord, 128)
	for n := 0; n < max; n++ {
		_, ok := runtime.GoroutineProfile(stk)
		if !ok {
			t.Fatalf("GoroutineProfile failed")
		}
	}

	// If the program didn't crash, we passed.
	atomic.StoreUint32(&stop, 1)
	wg.Wait()
}
Example #7
0
func main() {
	// arguments
	if len(os.Args) < 2 {
		fmt.Printf("usage: %s [server-listen_address] [local-server_address-socks_address]\n", os.Args[0])
		return
	}
	var serverSessionManagers []*SessionManager
	var localSessionManager *SessionManager
	serverDeliveries := make(map[int64]*Delivery)
	for _, arg := range os.Args[1:] {

		if strings.HasPrefix(arg, "server") { // start server
			parts := strings.Split(arg, "-")
			listener, err := NewDeliveryListener(parts[1])
			if err != nil {
				log.Fatal(err)
			}
			listener.OnSignal("notify:delivery", func(delivery *Delivery) {
				serverDeliveries[delivery.Source] = delivery
				delivery.CloseCallbacks = append(delivery.CloseCallbacks, func() {
					delete(serverDeliveries, delivery.Source)
				})
				m := NewSessionManager(delivery)
				serverSessionManagers = append(serverSessionManagers, m)
			})

		} else if strings.HasPrefix(arg, "local") { // start local
			parts := strings.Split(arg, "-")
			delivery, err := NewOutgoingDelivery(parts[1])
			if err != nil {
				log.Fatal(err)
			}
			localSessionManager = NewSessionManager(delivery)
			socksServer, err := NewSocksServer(parts[2])
			if err != nil {
				log.Fatal(err)
			}
			socksServer.OnSignal("client", func(conn net.Conn, hostPort string) {
				session, err := NewOutgoingSession(delivery, hostPort, conn)
				if err != nil {
					log.Fatal(err)
				}
				localSessionManager.Sessions[session.id] = session
				session.OnClose(func() {
					delete(localSessionManager.Sessions, session.id)
				})
			})

		} else if strings.HasPrefix(arg, "status") { // status
			parts := strings.Split(arg, "-")
			go func() {
				err := http.ListenAndServe(parts[1], nil)
				if err != nil {
					log.Fatal(err)
				}
			}()
			// web status
			http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
				p := func(format string, args ...interface{}) {
					fmt.Fprintf(w, format, args...)
				}
				// status
				var memStats runtime.MemStats
				runtime.ReadMemStats(&memStats)
				p("%d goroutines, %fm in use\n", runtime.NumGoroutine(), float64(memStats.Alloc)/1000000)
				p("load")
				for _, delivery := range serverDeliveries {
					p(" %f", delivery.Load)
				}
				p("\n")
				p("\n")
				// local sessions
				if localSessionManager != nil {
					p("%d local sessions\n", len(localSessionManager.Sessions))
					for _, session := range localSessionManager.Sessions {
						p("%v %v %s\n", session.localClosed, session.remoteClosed, session.hostPort)
					}
					p("\n")
				}
				// server sessions
				for _, manager := range serverSessionManagers {
					p("%d server sessions\n", len(manager.Sessions))
					for _, session := range manager.Sessions {
						p("%v %v %s\n", session.localClosed, session.remoteClosed, session.hostPort)
					}
					p("\n")
				}
				// goroutines
				p("stack traces\n")
				records := make([]runtime.StackRecord, runtime.NumGoroutine()*2)
				n, _ := runtime.GoroutineProfile(records)
				stats := make(map[string]int)
				for i := 0; i < n; i++ {
					stack := records[i].Stack()
					entries := make([]string, 0)
					for _, pc := range stack {
						f := runtime.FuncForPC(pc)
						file, line := f.FileLine(pc)
						if !strings.Contains(file, "gotunnel-ng") {
							continue
						}
						entries = append(entries, fmt.Sprintf("%s %d", file, line))
					}
					if len(entries) > 0 {
						s := strings.Join(entries, "\n")
						stats[s]++
					}
				}
				var traces []string
				for trace, _ := range stats {
					traces = append(traces, trace)
				}
				sort.Strings(traces)
				for _, trace := range traces {
					p("%d\n", stats[trace])
					p("%s\n", trace)
				}
			})
		} else {
			log.Fatalf("unknown argument %s", arg)
		}
	}

	<-(make(chan bool))
}