pax_global_header00006660000000000000000000000064147433163570014527gustar00rootroot0000000000000052 comment=98677121fa7b0e15e99a570e93c8e9ad9f245397 ocaml-mem_usage-0.1.2/000077500000000000000000000000001474331635700145625ustar00rootroot00000000000000ocaml-mem_usage-0.1.2/.github/000077500000000000000000000000001474331635700161225ustar00rootroot00000000000000ocaml-mem_usage-0.1.2/.github/workflows/000077500000000000000000000000001474331635700201575ustar00rootroot00000000000000ocaml-mem_usage-0.1.2/.github/workflows/doc.yml000066400000000000000000000011651474331635700214520ustar00rootroot00000000000000name: Doc build on: push: branches: - main jobs: build_doc: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v1 - name: Setup OCaml uses: ocaml/setup-ocaml@v3 with: ocaml-compiler: 4.14.x - name: Pin locally run: opam pin -y add --no-action . - name: Install locally run: opam install -y --with-doc mem_usage - name: Build doc run: opam exec dune build @doc - name: Deploy doc uses: JamesIves/github-pages-deploy-action@4.1.4 with: branch: gh-pages folder: _build/default/_doc/_html ocaml-mem_usage-0.1.2/.github/workflows/main.yml000066400000000000000000000007371474331635700216350ustar00rootroot00000000000000name: CI on: [push] jobs: cancel_previous_run: runs-on: ubuntu-latest steps: - name: Cancel Previous Runs uses: styfle/cancel-workflow-action@0.4.0 with: access_token: ${{ github.token }} build: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - name: Build and test module uses: savonet/build-and-test-ocaml-module@main ocaml-mem_usage-0.1.2/.gitignore000066400000000000000000000000161474331635700165470ustar00rootroot00000000000000.*.sw* _build ocaml-mem_usage-0.1.2/.ocamlformat000066400000000000000000000003371474331635700170720ustar00rootroot00000000000000version=0.25.1 profile = conventional break-separators = after space-around-lists = false doc-comments = before match-indent = 2 match-indent-nested = always parens-ite exp-grouping = preserve module-item-spacing = compact ocaml-mem_usage-0.1.2/CHANGES000066400000000000000000000007041474331635700155560ustar00rootroot000000000000000.1.2 (2025-01-18) ===== * Fixed compilation on freebsd. 0.1.1 (2024-04-17) ===== * Added private and swapped process memory. 0.1.0 (2024-01-31) ====== * Widen memory size integers (#4) * Allow compilation with OCaml 5 (#5) 0.0.4 (2022-06-28) ===== * Fixed buffer overflow using `fscanf` 0.0.3 (2022-04-30) ====== * Fix parsing of proc file on linux. 0.0.2 (2022-04-27) ====== * Fix segfault (#1) 0.0.1 (2022-02-14) ====== * Initial release 💝 ocaml-mem_usage-0.1.2/LICENSE000066400000000000000000000020551474331635700155710ustar00rootroot00000000000000MIT License Copyright (c) 2024 Savonet team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ocaml-mem_usage-0.1.2/README.md000066400000000000000000000022611474331635700160420ustar00rootroot00000000000000ocaml-mem_usage ============ ![GitHub](https://img.shields.io/github/license/savonet/ocaml-mem_usage) ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/savonet/ocaml-mem_usage/.github/workflows/main.yml?branch=main) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/savonet/ocaml-mem_usage) ocaml-mem_usage is a simple cross-platform OCaml module to return information on memory usage. Documentation: ============= The [API documentation is available here](https://www.liquidsoap.info/ocaml-mem_usage/mem_usage/index.html) Prerequisites: ============== - ocaml - dune - findlib See [dune-project](dune-project) file for versions. Installation: ============= The preferred installation method is via [opam](http://opam.ocaml.org/): ``` opam install mem_usage ``` This will install the latest release of `mem_usage`. If you wish to install the latest code from this repository, you can do: ``` opam install . ``` From within this repository. Compilation: ============ ``` dune build ``` Author: ======= This author of this software may be contacted by electronic mail at the following address: savonet-users@lists.sourceforge.net. ocaml-mem_usage-0.1.2/dune-project000066400000000000000000000005721474331635700171100ustar00rootroot00000000000000(lang dune 2.8) (version 0.1.2) (name mem_usage) (source (github savonet/ocaml-mem_usage)) (license MIT) (authors "Romain Beauxis ") (maintainers "The Savonet Team ") (generate_opam_files true) (package (name mem_usage) (synopsis "Cross-platform stats about memory usage") (depends (ocaml (>= 4.08)) dune) ) ocaml-mem_usage-0.1.2/lib/000077500000000000000000000000001474331635700153305ustar00rootroot00000000000000ocaml-mem_usage-0.1.2/lib/c_flags.freebsd.sexp000066400000000000000000000000311474331635700212320ustar00rootroot00000000000000("-I/usr/local/include") ocaml-mem_usage-0.1.2/lib/c_library_flags.freebsd.sexp000066400000000000000000000000371474331635700227640ustar00rootroot00000000000000("-L/usr/local/lib -lsysinfo") ocaml-mem_usage-0.1.2/lib/c_library_flags.mingw.sexp000066400000000000000000000000141474331635700224660ustar00rootroot00000000000000("-lpsapi") ocaml-mem_usage-0.1.2/lib/c_library_flags.mingw64.sexp000066400000000000000000000000141474331635700226400ustar00rootroot00000000000000("-lpsapi") ocaml-mem_usage-0.1.2/lib/dune000066400000000000000000000007461474331635700162150ustar00rootroot00000000000000(library (name mem_usage) (public_name mem_usage) (synopsis "Cross-platform memory usage information") (foreign_stubs (language c) (names mem_usage) (flags (:standard (:include c_flags.%{system}.sexp)))) (c_library_flags (:include c_library_flags.%{system}.sexp))) (rule (target c_flags.%{system}.sexp) (mode fallback) (action (write-file %{target} "()"))) (rule (target c_library_flags.%{system}.sexp) (mode fallback) (action (write-file %{target} "()"))) ocaml-mem_usage-0.1.2/lib/mem_usage.c000066400000000000000000000221651474331635700174440ustar00rootroot00000000000000// SPDX-FileCopyrightText: 2022 - 2024 Savonet team // // SPDX-License-Identifier: MIT #include #include #include #include #if defined(WIN32) #include #include #include #include typedef struct _PROCESS_MEMORY_COUNTERS_EX2 { DWORD cb; DWORD PageFaultCount; SIZE_T PeakWorkingSetSize; SIZE_T WorkingSetSize; SIZE_T QuotaPeakPagedPoolUsage; SIZE_T QuotaPagedPoolUsage; SIZE_T QuotaPeakNonPagedPoolUsage; SIZE_T QuotaNonPagedPoolUsage; SIZE_T PagefileUsage; SIZE_T PeakPagefileUsage; SIZE_T PrivateUsage; SIZE_T PrivateWorkingSetSize; ULONG64 SharedCommitUsage; } PROCESS_MEMORY_COUNTERS_EX2; CAMLprim value ocaml_mem_usage_mem_usage(value unit) { CAMLparam0(); CAMLlocal1(ret); MEMORYSTATUSEX mem_info; PROCESS_MEMORY_COUNTERS_EX2 pmc; DWORDLONG total_virtual_memory; DWORDLONG total_used_virtual_memory; DWORDLONG total_physical_memory; DWORDLONG total_used_physical_memory; SIZE_T process_virtual_memory; SIZE_T process_physical_memory; SIZE_T process_private_memory; SIZE_T process_swapped_memory; caml_release_runtime_system(); mem_info.dwLength = sizeof(MEMORYSTATUSEX); GlobalMemoryStatusEx(&mem_info); total_virtual_memory = mem_info.ullTotalPageFile; total_used_virtual_memory = mem_info.ullTotalPageFile - mem_info.ullAvailPageFile; total_physical_memory = mem_info.ullTotalPhys; total_used_physical_memory = mem_info.ullTotalPhys - mem_info.ullAvailPhys; GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS *)&pmc, sizeof(pmc)); process_virtual_memory = pmc.PrivateUsage; process_physical_memory = pmc.WorkingSetSize; process_private_memory = pmc.PrivateWorkingSetSize; process_swapped_memory = pmc.PagefileUsage; caml_acquire_runtime_system(); ret = caml_alloc_tuple(8); Store_field(ret, 0, Val_long(total_virtual_memory)); Store_field(ret, 1, Val_long(total_physical_memory)); Store_field(ret, 2, Val_long(total_used_virtual_memory)); Store_field(ret, 3, Val_long(total_used_physical_memory)); Store_field(ret, 4, Val_long(process_virtual_memory)); Store_field(ret, 5, Val_long(process_physical_memory)); Store_field(ret, 6, Val_long(process_private_memory)); Store_field(ret, 7, Val_long(process_swapped_memory)); CAMLreturn(ret); } #elif defined(__APPLE__) #include #include #include #include #include #include #include #include #include #include void private_pages(unsigned int *pages_resident, unsigned int *pages_swapped_out) { mach_vm_address_t address = 0; mach_vm_size_t size = 0; uint32_t depth = 2048; vm_region_submap_info_data_64_t info; mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64; kern_return_t kr; *pages_resident = 0; *pages_swapped_out = 0; while (1) { kr = mach_vm_region_recurse(mach_task_self(), &address, &size, &depth, (vm_region_recurse_info_t)&info, &count); if (kr != KERN_SUCCESS || size == 0) break; if (info.share_mode == SM_PRIVATE) { *pages_resident += info.pages_resident; *pages_swapped_out += info.pages_swapped_out; } address += size; } } CAMLprim value ocaml_mem_usage_mem_usage(value unit) { CAMLparam0(); CAMLlocal1(ret); struct statfs stats; uint64_t total_virtual_memory, total_physical_memory, total_used_physical_memory, total_used_virtual_memory, process_physical_memory, process_virtual_memory, process_private_memory, process_swapped_memory; struct xsw_usage vmem_usage = {0}; size_t size = sizeof(vmem_usage); struct task_basic_info t_info; mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; vm_size_t page_size; mach_port_t mach_port; mach_msg_type_number_t count; vm_statistics64_data_t vm_stats; int pagesize; unsigned int pages_resident, pages_swapped_out; caml_release_runtime_system(); if (statfs("/", &stats) != 0) { fprintf(stderr, "Error while getting free swap space.\n"); total_virtual_memory = 0; } else { total_virtual_memory = (uint64_t)stats.f_bsize * stats.f_bfree; } if (sysctlbyname("vm.swapusage", &vmem_usage, &size, NULL, 0) != 0) { fprintf(stderr, "Error while getting swap usage.\n"); total_used_virtual_memory = 0; } else { total_used_virtual_memory = vmem_usage.xsu_used; } if (task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count)) { fprintf(stderr, "Unable to get virtual memory currently used by the process.\n"); process_physical_memory = 0; process_virtual_memory = 0; } else { process_physical_memory = t_info.resident_size; process_virtual_memory = t_info.virtual_size; } mach_port = mach_host_self(); count = sizeof(vm_stats) / sizeof(natural_t); if (host_page_size(mach_port, &page_size) != KERN_SUCCESS) { fprintf(stderr, "Unable to get host page size.\n"); total_physical_memory = 0; total_used_physical_memory = 0; } else { if (host_statistics64(mach_port, HOST_VM_INFO, (host_info64_t)&vm_stats, &count) != KERN_SUCCESS) { fprintf(stderr, "Unable to get host stats.\n"); total_physical_memory = 0; total_used_physical_memory = 0; } else { total_physical_memory = vm_stats.free_count * (int64_t)page_size; total_used_physical_memory = ((int64_t)vm_stats.active_count + (int64_t)vm_stats.inactive_count + (int64_t)vm_stats.wire_count) * (int64_t)page_size; } } pagesize = getpagesize(); private_pages(&pages_resident, &pages_swapped_out); process_private_memory = pages_resident * pagesize; process_swapped_memory = pages_swapped_out * pagesize; caml_acquire_runtime_system(); ret = caml_alloc_tuple(8); ; Store_field(ret, 0, Val_long(total_virtual_memory)); Store_field(ret, 1, Val_long(total_physical_memory)); Store_field(ret, 2, Val_long(total_used_virtual_memory)); Store_field(ret, 3, Val_long(total_used_physical_memory)); Store_field(ret, 4, Val_long(process_virtual_memory)); Store_field(ret, 5, Val_long(process_physical_memory)); Store_field(ret, 6, Val_long(process_private_memory)); Store_field(ret, 7, Val_long(process_swapped_memory)); CAMLreturn(ret); } #else #include #include #include #include #include CAMLprim value ocaml_mem_usage_mem_usage(value unit) { CAMLparam0(); CAMLlocal1(ret); struct sysinfo memInfo; uint64_t total_virtual_memory, total_physical_memory, total_used_virtual_memory, total_used_physical_memory; unsigned long long process_virtual_memory, process_physical_memory, process_private_memory, process_swapped_memory, tmp; FILE *file; char buffer[1024] = ""; caml_release_runtime_system(); sysinfo(&memInfo); total_physical_memory = memInfo.totalram; total_physical_memory *= memInfo.mem_unit; total_virtual_memory = memInfo.totalram; total_virtual_memory += memInfo.totalswap; total_virtual_memory *= memInfo.mem_unit; total_used_virtual_memory = memInfo.totalram - memInfo.freeram; total_used_virtual_memory += memInfo.totalswap - memInfo.freeswap; total_used_virtual_memory *= memInfo.mem_unit; total_used_physical_memory = memInfo.totalram - memInfo.freeram; total_used_physical_memory *= memInfo.mem_unit; file = fopen("/proc/self/status", "r"); if (file) { while (fscanf(file, " %1023s", buffer) == 1) { if (strcmp(buffer, "VmSize:") == 0) { if (fscanf(file, " %lld", &process_virtual_memory) != 1) process_virtual_memory = 0; process_virtual_memory *= 1024; continue; } if (strcmp(buffer, "VmRSS:") == 0) { if (fscanf(file, " %lld", &process_physical_memory) != 1) process_physical_memory = 0; process_physical_memory *= 1024; continue; } } fclose(file); } process_private_memory = 0; process_swapped_memory = 0; file = fopen("/proc/self/smaps", "r"); if (file) { while (fscanf(file, " %1023s", buffer) == 1) { if (strcmp(buffer, "Private_Dirty:") == 0) { if (fscanf(file, " %lld", &tmp) != 1) tmp = 0; process_private_memory += tmp * 1024; continue; } if (strcmp(buffer, "Swap:") == 0) { if (fscanf(file, " %lld", &tmp) != 1) tmp = 0; process_swapped_memory += tmp * 1024; continue; } } fclose(file); } caml_acquire_runtime_system(); ret = caml_alloc_tuple(8); Store_field(ret, 0, Val_long(total_virtual_memory)); Store_field(ret, 1, Val_long(total_physical_memory)); Store_field(ret, 2, Val_long(total_used_virtual_memory)); Store_field(ret, 3, Val_long(total_used_physical_memory)); Store_field(ret, 4, Val_long(process_virtual_memory)); Store_field(ret, 5, Val_long(process_physical_memory)); Store_field(ret, 6, Val_long(process_private_memory)); Store_field(ret, 7, Val_long(process_swapped_memory)); CAMLreturn(ret); } #endif ocaml-mem_usage-0.1.2/lib/mem_usage.ml000066400000000000000000000033211474331635700176230ustar00rootroot00000000000000(* * SPDX-FileCopyrightText: 2022 - 2024 Savonet team * * SPDX-License-Identifier: MIT *) type t = { total_virtual_memory : int; total_physical_memory : int; total_used_virtual_memory : int; total_used_physical_memory : int; process_virtual_memory : int; process_physical_memory : int; process_private_memory : int; process_swapped_memory : int; } external info : unit -> t = "ocaml_mem_usage_mem_usage" let byte_units = ["B"; "kB"; "MB"; "GB"; "TB"; "PB"; "EB"; "ZB"; "YB"] let bibyte_units = ["B"; "kiB"; "MiB"; "GiB"; "TiB"; "PiB"; "EiB"; "ZiB"; "YiB"] let bit_units = ["b"; "kbit"; "Mbit"; "Gbit"; "Tbit"; "Pbit"; "Ebit"; "Zbit"; "Ybit"] let bibit_units = ["b"; "kibit"; "Mibit"; "Gibit"; "Tibit"; "Pibit"; "Eibit"; "Zibit"; "Yibit"] let prettify_bytes ?(float_printer = Printf.sprintf "%.02f") ?(signed = false) ?(bits = false) ?(binary = false) bytes = let units = match (bits, binary) with | true, true -> bibit_units | true, false -> bit_units | false, true -> bibyte_units | false, false -> byte_units in let prefix, bytes = if bytes < 0 then ("-", -bytes) else ((if signed then "+" else ""), bytes) in if bytes = 0 then Printf.sprintf "%s0 %s" prefix (List.hd units) else ( let exponent = Float.floor (if binary then log (float bytes) /. log 1024. else log10 (float bytes) /. 3.) in let unit_index = if List.length units - 1 < int_of_float exponent then List.length units - 1 else int_of_float exponent in let bytes = float bytes /. Float.pow (if binary then 1024. else 1000.) exponent in Printf.sprintf "%s%s %s" prefix (float_printer bytes) (List.nth units unit_index)) ocaml-mem_usage-0.1.2/lib/mem_usage.mli000066400000000000000000000010111474331635700177660ustar00rootroot00000000000000(* * SPDX-FileCopyrightText: 2022 - 2024 Savonet team * * SPDX-License-Identifier: MIT *) type t = { total_virtual_memory : int; total_physical_memory : int; total_used_virtual_memory : int; total_used_physical_memory : int; process_virtual_memory : int; process_physical_memory : int; process_private_memory : int; process_swapped_memory : int; } val info : unit -> t val prettify_bytes : ?float_printer:(float -> string) -> ?signed:bool -> ?bits:bool -> ?binary:bool -> int -> string ocaml-mem_usage-0.1.2/mem_usage.opam000066400000000000000000000013511474331635700174020ustar00rootroot00000000000000# This file is generated by dune, edit dune-project instead opam-version: "2.0" version: "0.1.2" synopsis: "Cross-platform stats about memory usage" maintainer: ["The Savonet Team "] authors: ["Romain Beauxis "] license: "MIT" homepage: "https://github.com/savonet/ocaml-mem_usage" bug-reports: "https://github.com/savonet/ocaml-mem_usage/issues" build: [ ["dune" "subst"] {dev} [ "dune" "build" "-p" name "-j" jobs "@install" "@runtest" {with-test} "@doc" {with-doc} ] ] dev-repo: "git+https://github.com/savonet/ocaml-mem_usage.git" depends: [ "conf-sysinfo" {os = "freebsd"} "ocaml" {>= "4.08"} "dune" {>= "2.8"} "odoc" {with-doc} ] ocaml-mem_usage-0.1.2/mem_usage.opam.template000066400000000000000000000001551474331635700212150ustar00rootroot00000000000000depends: [ "conf-sysinfo" {os = "freebsd"} "ocaml" {>= "4.08"} "dune" {>= "2.8"} "odoc" {with-doc} ] ocaml-mem_usage-0.1.2/test/000077500000000000000000000000001474331635700155415ustar00rootroot00000000000000ocaml-mem_usage-0.1.2/test/dune000066400000000000000000000000531474331635700164150ustar00rootroot00000000000000(test (name test) (libraries mem_usage)) ocaml-mem_usage-0.1.2/test/test.ml000066400000000000000000000020571474331635700170560ustar00rootroot00000000000000(* * SPDX-FileCopyrightText: 2022 - 2024 Savonet team * * SPDX-License-Identifier: MIT *) let () = let { Mem_usage.total_virtual_memory; total_physical_memory; total_used_virtual_memory; total_used_physical_memory; process_virtual_memory; process_physical_memory; process_private_memory; process_swapped_memory; } = Mem_usage.info () in Printf.printf {| Total virtual memory: %s Total physical memory: %s Used virtual memory: %s Used physical memory: %s Process virtual memory: %s Process physical memory: %s Process private memory: %s Process swapped memory: %s |} (Mem_usage.prettify_bytes total_virtual_memory) (Mem_usage.prettify_bytes total_physical_memory) (Mem_usage.prettify_bytes total_used_virtual_memory) (Mem_usage.prettify_bytes total_used_physical_memory) (Mem_usage.prettify_bytes process_virtual_memory) (Mem_usage.prettify_bytes process_physical_memory) (Mem_usage.prettify_bytes process_private_memory) (Mem_usage.prettify_bytes process_swapped_memory)