Andrea Campanella | 096fa59 | 2022-02-03 12:07:35 +0100 | [diff] [blame] | 1 | Memory Usage investigation |
| 2 | ========================== |
| 3 | |
| 4 | This page shows how to analyze the memory consumption of a VOLTHA container (written in Go) by using a |
| 5 | custom built image of the container and the ``pprof`` tool, provided by the GO Language. |
| 6 | |
| 7 | |
| 8 | Build an instrumented docker image |
| 9 | ---------------------------------- |
| 10 | |
| 11 | If the Makefile and the Helm Charts of your image support building and deploying profiled images (should be the case), |
| 12 | you can create a profiled image, via the ``make docker-build`` target adding the option ``BUILD_PROFILED=true``. |
| 13 | The command will generate two images- the normal and the profiled one |
| 14 | Following is an example for the ``voltha-openonu-adapter-go``, please customize the values according to your |
| 15 | docker registry and desired tag: |
| 16 | |
| 17 | .. code:: bash |
| 18 | |
| 19 | DOCKER_REGISTRY="hhildebr/" DOCKER_TAG="hh-dev" BUILD_PROFILED=true make docker-build |
| 20 | |
| 21 | .. code:: bash |
| 22 | |
| 23 | bbsim@bbsim:~$ docker images |
| 24 | REPOSITORY TAG IMAGE ID CREATED SIZE |
| 25 | hhildebr/voltha-openonu-adapter-go hh-dev-profile e142bba3afea 2 hours ago 725MB |
| 26 | hhildebr/voltha-openonu-adapter-go hh-dev 8b6c5436a97d 2 hours ago 37.8MB |
| 27 | |
| 28 | Deploy the instrumented image |
| 29 | ----------------------------- |
| 30 | |
| 31 | Now you can deploy VOLTHA by using the custom ``<image_name>-profile`` via helm flag. |
| 32 | Also the profiler flag must be activated. |
| 33 | Following is a snippet to put into a ``values.yaml`` file. |
| 34 | |
| 35 | .. code:: bash |
| 36 | |
| 37 | voltha-adapter-openonu: |
| 38 | images: |
| 39 | adapter_open_onu_go: |
| 40 | repository: hhildebr/voltha-openonu-adapter-go |
| 41 | tag: hh-dev-profile |
| 42 | pullPolicy: "Never" |
| 43 | profiler: |
| 44 | enabled: true |
| 45 | |
| 46 | Verify and expose the profiler endpoint |
| 47 | --------------------------------------- |
| 48 | |
| 49 | To verify that the associated profiler server was started successfully and the endpoint is exposed in kubernetes, |
| 50 | use the following command: |
| 51 | |
| 52 | .. code:: bash |
| 53 | |
| 54 | kubectl get svc --all-namespaces |
| 55 | |
| 56 | The expected output is: |
| 57 | |
| 58 | .. code:: bash |
| 59 | |
| 60 | NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE |
| 61 | … |
| 62 | voltha voltha-voltha-adapter-openonu-profiler ClusterIP None <none> 6060/TCP 2h |
| 63 | … |
| 64 | |
| 65 | To then be able to communicate with the profile server from your host system, you have to configure an |
| 66 | appropriate port forwarding. An example is the following: |
| 67 | |
| 68 | .. code:: bash |
| 69 | |
| 70 | kubectl -n voltha port-forward --address 0.0.0.0 svc/voltha1-voltha-adapter-openonu-profiler 6060:6060 |
| 71 | |
| 72 | Use the pprof tool |
| 73 | ------------------ |
| 74 | |
| 75 | Static Mode |
| 76 | ^^^^^^^^^^^ |
| 77 | |
| 78 | The profiling tool can be now interacted with and data retrieved. |
| 79 | Following is an example of how to get the heap usage of the container and save it to a file: |
| 80 | |
| 81 | .. code:: bash |
| 82 | |
| 83 | curl http://127.0.0.1:6060/debug/pprof/heap > onu-go-heap.pprof |
| 84 | |
| 85 | To get a first idea of the system's status, a graphical overview of the heap usage can be created from the extracted |
| 86 | data using the ``pprof`` tool and displayed in the browser. |
| 87 | |
| 88 | .. code:: bash |
| 89 | |
| 90 | go tool pprof -http=:8080 onu-go-heap.pprof |
| 91 | |
| 92 | In order to save the graphical representation of the data permanently, an image file can be created from it |
| 93 | (PDF-format is also supported): |
| 94 | |
| 95 | .. code:: bash |
| 96 | |
| 97 | go tool pprof -png onu-go-heap.pprof |
| 98 | |
| 99 | Following is an example with heap data collected after hundreds of cycles of startup and deletion |
| 100 | of multiple BBSIM ONUs. The individual objects/functions can be seen there in relation to each other. |
| 101 | Already by the size of the boxes you can recognize the objects/functions where to find the memory leaks. |
| 102 | |
| 103 | .. figure:: ../_static/1_graph_with_mem_leak.png |
| 104 | :alt: Graphical representation of memory usage |
| 105 | :width: 70% |
| 106 | :align: center |
| 107 | |
| 108 | Graphical representation of memory usage |
| 109 | |
| 110 | Interactive Mode |
| 111 | ^^^^^^^^^^^^^^^^ |
| 112 | |
| 113 | To start a detailed investigation, ``pprof`` is invoked in interactive mode. |
| 114 | Since pprof assumes by default that the code belonging to the UUT can be found in the /go/src directory, |
| 115 | this path part must be removed using the trim_path option and replaced with the actual directory part using |
| 116 | the source_path option. |
| 117 | Following is an example for the openonu adapter: |
| 118 | |
| 119 | .. code:: bash |
| 120 | |
| 121 | go tool pprof -source_path /home/bbsim/temp_pperf/voltha-openonu-adapter-go -trim_path /go/src /mnt/shared/onu-go-heap.pprof |
| 122 | |
| 123 | by using the ``top`` command one can see which are the main originators of memory leaks, |
| 124 | observing the the first ten objects/functions displayed: |
| 125 | |
| 126 | .. figure:: ../_static/2_top_with_mem_leak.png |
| 127 | :alt: Ten highest memory functions |
| 128 | :width: 80% |
| 129 | :align: center |
| 130 | |
| 131 | Ten highest memory functions |
| 132 | |
| 133 | If more object/functions are to be displayed, simply add the desired number to the command - e.g. ``top100``. |
| 134 | |
| 135 | |
| 136 | The next step is to use the ``list <function_name>`` command to view the detailed memory allocations. |
| 137 | |
| 138 | Example Memory leak analysis and fix |
| 139 | ------------------------------------ |
| 140 | Following is an example applied for the number one of the top10, function ``NewOnuDeviceEntry``. |
| 141 | |
| 142 | .. figure:: ../_static/3_list_with_mem_leak.png |
| 143 | :alt: List function details before optimization |
| 144 | :width: 80% |
| 145 | :align: center |
| 146 | |
| 147 | List function details before optimization |
| 148 | |
| 149 | Since the single allocation of ``onuDeviceEntry.omciRebootMessageReceivedChannel`` should occupy at most 100kB of |
| 150 | heap memory (2048 standard OMCI messages), we can conclude that the 85.90MB of occupied memory represents more |
| 151 | than 850 instances of ``onuDeviceEntry`` not deleted by the GC. |
| 152 | |
| 153 | After removing the cause of the memory leak the same test with hundreds of cycles of startup and deletion of multiple |
| 154 | BBSIM ONUs shows that the issue has been solved. Having a look at the retrieved pprof data shows a significant |
| 155 | decrease of memory consumption, about 10MB vs 744MB without the patch: |
| 156 | |
| 157 | .. figure:: ../_static/4_top_without_mem_leak.png |
| 158 | :alt: List function details after optimization |
| 159 | :width: 70% |
| 160 | :align: center |
| 161 | |
| 162 | List function details after optimization |