(lc *z.Closer)
| 733 | } |
| 734 | |
| 735 | func MonitorMemoryMetrics(lc *z.Closer) { |
| 736 | defer lc.Done() |
| 737 | ticker := time.Tick(time.Minute) |
| 738 | fastTicker := time.Tick(time.Second) |
| 739 | |
| 740 | update := func() { |
| 741 | // ReadMemStats stops the world which is expensive especially when the |
| 742 | // heap is large. So don't call it too frequently. Calling it every |
| 743 | // minute is OK. |
| 744 | var ms runtime.MemStats |
| 745 | runtime.ReadMemStats(&ms) |
| 746 | |
| 747 | inUse := ms.HeapInuse + ms.StackInuse |
| 748 | // From runtime/mstats.go: |
| 749 | // HeapIdle minus HeapReleased estimates the amount of memory |
| 750 | // that could be returned to the OS, but is being retained by |
| 751 | // the runtime so it can grow the heap without requesting more |
| 752 | // memory from the OS. If this difference is significantly |
| 753 | // larger than the heap size, it indicates there was a recent |
| 754 | // transient spike in live heap size. |
| 755 | idle := ms.HeapIdle - ms.HeapReleased |
| 756 | |
| 757 | ostats.Record(context.Background(), |
| 758 | MemoryInUse.M(int64(inUse)), |
| 759 | MemoryIdle.M(int64(idle)), |
| 760 | MemoryProc.M(int64(getMemUsage()))) |
| 761 | } |
| 762 | updateAlloc := func() { |
| 763 | ostats.Record(context.Background(), MemoryAlloc.M(z.NumAllocBytes())) |
| 764 | } |
| 765 | // Call update immediately so that Dgraph reports memory stats without |
| 766 | // having to wait for the first tick. |
| 767 | update() |
| 768 | updateAlloc() |
| 769 | |
| 770 | for { |
| 771 | select { |
| 772 | case <-lc.HasBeenClosed(): |
| 773 | return |
| 774 | case <-fastTicker: |
| 775 | updateAlloc() |
| 776 | case <-ticker: |
| 777 | update() |
| 778 | } |
| 779 | } |
| 780 | } |
| 781 | |
| 782 | func getMemUsage() int { |
| 783 | if runtime.GOOS != "linux" { |
no test coverage detected