├── LICENSE ├── Makefile ├── README.md ├── darwin ├── cpu_info.c ├── cpu_memory_by_process.c ├── cpu_usage_info.c ├── disk_info.c ├── io_analysis.c ├── load_avg.c ├── memory_info.c ├── network_info.c ├── os_info.c ├── process_info.c └── system_stats_utils.c ├── linux ├── cpu_info.c ├── cpu_memory_by_process.c ├── cpu_usage_info.c ├── disk_info.c ├── io_analysis.c ├── load_avg.c ├── memory_info.c ├── network_info.c ├── os_info.c ├── process_info.c └── system_stats_utils.c ├── system_stats--1.0--2.0.sql ├── system_stats--1.0.sql ├── system_stats--2.0--3.0.sql ├── system_stats--2.0.sql ├── system_stats--3.0.sql ├── system_stats.c ├── system_stats.control ├── system_stats.h ├── system_stats.sln ├── system_stats.vcxproj ├── system_stats.vcxproj.filters ├── uninstall_system_stats.sql └── windows ├── cpu_info.c ├── cpu_memory_by_process.c ├── cpu_usage_info.c ├── disk_info.c ├── io_analysis.c ├── load_avg.c ├── memory_info.c ├── network_info.c ├── os_info.c ├── process_info.c └── system_stats_utils.c /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 - 2020, EnterpriseDB Corporation 2 | 3 | Permission to use, copy, modify, and distribute this software and its 4 | documentation for any purpose, without fee, and without a written agreement is 5 | hereby granted, provided that the above copyright notice and this paragraph and 6 | the following two paragraphs appear in all copies. 7 | 8 | IN NO EVENT SHALL EnterpriseDB Corporation BE LIABLE TO ANY PARTY FOR DIRECT, 9 | INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST 10 | PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 11 | EnterpriseDB Corporation HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | 13 | EnterpriseDB Corporation SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT 14 | NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 15 | PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND 16 | EnterpriseDB Corporation HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, 17 | UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 18 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | MODULE_big = system_stats 2 | 3 | #Detect OS type and accordingly include the source files for compilation 4 | UNAME := $(shell uname) 5 | 6 | OS_PLATFORM := $(shell echo $(UNAME) | tr '[:upper:]' '[:lower:]') 7 | 8 | $(info "Platform is: $(OS_PLATFORM)") 9 | 10 | # FreeBSD is not supported so do not build it 11 | ifneq (,$(findstring freebsd, $(OS_PLATFORM))) 12 | $(error FreeBSD is not supported by this extension) 13 | endif 14 | 15 | # Solaris is not supported so do not build it 16 | ifneq (,$(findstring solaris, $(OS_PLATFORM))) 17 | $(error Solaris is not supported by this extension) 18 | endif 19 | ifneq (,$(findstring sparc, $(OS_PLATFORM))) 20 | $(error Solaris is not supported by this extension) 21 | endif 22 | 23 | # HP-UX is not supported so do not build it 24 | ifneq (,$(findstring hp-ux, $(OS_PLATFORM))) 25 | $(error HP-UX is not supported by this extension) 26 | endif 27 | 28 | ifeq ($(UNAME), Linux) 29 | OBJS = \ 30 | system_stats.o \ 31 | linux/system_stats_utils.o \ 32 | linux/disk_info.o \ 33 | linux/io_analysis.o \ 34 | linux/cpu_info.o \ 35 | linux/cpu_usage_info.o \ 36 | linux/os_info.o \ 37 | linux/memory_info.o \ 38 | linux/load_avg.o \ 39 | linux/process_info.o \ 40 | linux/network_info.o \ 41 | linux/cpu_memory_by_process.o 42 | 43 | HEADERS = system_stats.h 44 | 45 | endif 46 | 47 | ifeq ($(UNAME), Darwin) 48 | OBJS = \ 49 | system_stats.o \ 50 | darwin/system_stats_utils.o \ 51 | darwin/disk_info.o \ 52 | darwin/io_analysis.o \ 53 | darwin/cpu_info.o \ 54 | darwin/cpu_usage_info.o \ 55 | darwin/os_info.o \ 56 | darwin/memory_info.o \ 57 | darwin/load_avg.o \ 58 | darwin/process_info.o \ 59 | darwin/network_info.o \ 60 | darwin/cpu_memory_by_process.o 61 | 62 | HEADERS = system_stats.h 63 | 64 | PG_LDFLAGS= -framework IOKit -framework CoreFoundation 65 | endif 66 | 67 | EXTENSION = system_stats 68 | DATA = system_stats--1.0--2.0.sql system_stats--1.0.sql system_stats--2.0.sql system_stats--2.0--3.0.sql system_stats--3.0.sql uninstall_system_stats.sql 69 | PGFILEDESC = "system_stats - system statistics functions" 70 | 71 | 72 | REGRESS = system_stats 73 | 74 | ifndef USE_PGXS 75 | top_builddir = ../.. 76 | makefile_global = $(top_builddir)/src/Makefile.global 77 | ifeq "$(wildcard $(makefile_global))" "" 78 | USE_PGXS = 1 # use pgxs if not in contrib directory 79 | endif 80 | endif 81 | 82 | ifdef USE_PGXS 83 | PG_CONFIG = pg_config 84 | PGXS := $(shell $(PG_CONFIG) --pgxs) 85 | include $(PGXS) 86 | else 87 | subdir = contrib/$(MODULE_big) 88 | include $(makefile_global) 89 | include $(top_srcdir)/contrib/contrib-global.mk 90 | endif 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # System Statistics 2 | *system_stats* is a Postgres extension that provides functions to access system 3 | level statistics that can be used for monitoring. It supports Linux, macOS and 4 | Windows. 5 | 6 | Note that not all values are relevant on all operating systems. In such cases 7 | NULL is returned for affected values. 8 | 9 | *Copyright (c) 2019 - 2023, EnterpriseDB Corporation. All Rights Reserved.* 10 | 11 | ## Building and Installing 12 | 13 | ### Linux and macOS 14 | The module can be built using the PGXS framework: 15 | 16 | - Unpack the file archive in a suitable directory. 17 | - Ensure the PATH environment variable includes the directory containing the 18 | pg_config binary for the PostgreSQL installation you wish to build against. 19 | - Compile and install the code. 20 | 21 | For example: 22 | 23 | tar -zxvf system_stats-1.0.tar.gz 24 | cd system_stats-1.0 25 | PATH="/usr/local/pgsql/bin:$PATH" make USE_PGXS=1 26 | sudo PATH="/usr/local/pgsql/bin:$PATH" make install USE_PGXS=1 27 | 28 | ### Windows 29 | The module built using the Visual Studio project file: 30 | 31 | - Unpack the extensions files in $PGSRC/contrib/system_stats 32 | - Set PG_INCLUDE_DIR and PG_LIB_DIR environment variables to make sure the 33 | PostgreSQL include and lib directories can be found for compilation. For 34 | example: 35 | 36 | PG_INCLUDE_DIR=C:\Program Files\PostgreSQL\12\include 37 | PG_LIB_DIR=C:\Program Files\PostgreSQL\12\lib 38 | 39 | - Open the Visual Studio project file "system_stats.vcxproj" and build the 40 | project. 41 | 42 | ### Installing the Extension 43 | Once the code has been built and installed, you can install the extension in 44 | a database using the following SQL command: 45 | 46 | CREATE EXTENSION system_stats; 47 | 48 | ### Security 49 | Due to the nature of the information returned by these functions, access is 50 | restricted to superusers and members of the monitor_system_stats role which 51 | will be created when the extension is installed. The monitor_system_stats 52 | role will not be removed when you run DROP EXTENSION. This means that any 53 | users or roles that were granted permissions to the monitor_system_stats role 54 | will still have those permissions even after the extension has been dropped. 55 | To allow users to access the functions without granting them superuser access, 56 | add them to the monitor_system_stats role. For example: 57 | 58 | GRANT monitor_system_stats to nagios; 59 | 60 | User can grant execute rights for all the below functions to `pg_monitor` role explicitly 61 | 62 | e.g. 63 | 64 | GRANT EXECUTE ON FUNCTION pg_sys_os_info() TO pg_monitor; 65 | 66 | ## Functions 67 | The following functions are provided to fetch system level statistics for all 68 | platforms. 69 | 70 | ### pg_sys_os_info 71 | This interface allows the user to get operating system statistics. 72 | 73 | ### pg_sys_cpu_info 74 | This interface allows the user to get CPU information. 75 | 76 | ### pg_sys_cpu_usage_info 77 | This interface allows the user to get CPU usage information. Values are a 78 | percentage of time spent by CPUs for all operations. 79 | 80 | ### pg_sys_memory_info 81 | This interface allows the user to get memory usage information. All the values 82 | are in bytes. 83 | 84 | ### pg_sys_io_analysis_info 85 | This interface allows the user to get an I/O analysis of block devices. 86 | 87 | ### pg_sys_disk_info 88 | This interface allows the user to get the disk information. 89 | 90 | ### pg_sys_load_avg_info 91 | This interface allows the user to get the average load of the system over 1, 5, 92 | 10 and 15 minute intervals. 93 | 94 | ### pg_sys_process_info 95 | This interface allows the user to get process information. 96 | 97 | ### pg_sys_network_info 98 | This interface allows the user to get network interface information. 99 | 100 | ### pg_sys_cpu_memory_by_process 101 | This interface allows the user to get the CPU and memory information for each 102 | process ID. 103 | 104 | NOTE: macOS does not allow access to to process information for other users. 105 | e.g. If the database server is running as the postgres user, this function 106 | will fetch information only for processes owned by the postgres user. 107 | Other processes will be listed and include only the process ID and name; 108 | other columns will be NULL. 109 | 110 | 111 | ## Detailed output of each function 112 | 113 | ### pg_sys_os_info 114 | - Name 115 | - Version 116 | - Host name 117 | - Domain name 118 | - Handle count 119 | - Process count 120 | - Thread count 121 | - Architecture 122 | - Last bootup time 123 | - Uptime in seconds 124 | 125 | ### pg_sys_cpu_info 126 | - Vendor 127 | - Description 128 | - Model name 129 | - Processor type 130 | - Logical processor 131 | - Physical processor 132 | - Number of cores 133 | - Architecture 134 | - Clock speed in hz 135 | - CPU type 136 | - CPU family 137 | - Byte order 138 | - L1d cache size 139 | - L1i cache size 140 | - L2 cache size 141 | - L3 cache size 142 | 143 | ### pg_sys_cpu_usage_info 144 | - Percent time spent in processing usermode normal process 145 | - Percent time spent in processing usermode niced process 146 | - Percent time spent in kernel mode process 147 | - Percent time spent in idle mode 148 | - Percent time spent in io completion 149 | - Percent time spent in servicing interrupt 150 | - Percent time spent in servicing software interrupt 151 | - Percent user time spent 152 | - Percent processor time spent 153 | - Percent privileged time spent 154 | - Percent interrupt time spent 155 | 156 | ### pg_sys_memory_info 157 | - Total memory 158 | - Used memory 159 | - Free memory 160 | - Total swap memory 161 | - Used swap memory 162 | - Free swap memory 163 | - Total cache memory 164 | - Total kernel memory 165 | - Kernel paged memory 166 | - Kernel non paged memory 167 | - Total page file 168 | - Available page file 169 | 170 | ### pg_sys_io_analysis_info 171 | - Block device name 172 | - Total number of reads 173 | - Total number of writes 174 | - Read bytes 175 | - Written bytes 176 | - Time spent in milliseconds for reading 177 | - Time spent in milliseconds for writing 178 | 179 | ### pg_sys_disk_info 180 | - File system of the disk 181 | - File system type 182 | - Mount point for the file system 183 | - Drive letter 184 | - Drive type 185 | - Total space in bytes 186 | - Used space in bytes 187 | - Available space in bytes 188 | - Number of total inodes 189 | - Number of used inodes 190 | - Number of free inodes 191 | 192 | ### pg_sys_load_avg_info 193 | - 1 minute load average 194 | - 5 minute load average 195 | - 10 minute load average 196 | - 15 minute load average 197 | 198 | ### pg_sys_process_info 199 | - Number of total processes 200 | - Number of running processes 201 | - Number of sleeping processes 202 | - Number of stopped processes 203 | - Number of zombie processes 204 | 205 | ### pg_sys_network_info 206 | - Name of the interface_name 207 | - ipv4 address of the interface 208 | - Number of total bytes transmitted 209 | - Number of total packets transmitted 210 | - Number of transmit errors by this network device 211 | - Number of packets dropped during transmission 212 | - Number of total bytes received 213 | - Number of total packets received 214 | - Number of receive errors by this network device 215 | - Number of packets dropped by this network device 216 | - Interface speed in mbps 217 | 218 | ### pg_sys_cpu_memory_by_process 219 | - PID of the process 220 | - Process name 221 | - CPU usage in bytes 222 | - Memory usage in bytes 223 | - Total memory used in bytes 224 | -------------------------------------------------------------------------------- /darwin/cpu_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * cpu_info.c 3 | * System CPU information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | 16 | void ReadCPUInformation(Tuplestorestate *tupstore, TupleDesc tupdesc) 17 | { 18 | Datum values[Natts_cpu_info]; 19 | bool nulls[Natts_cpu_info]; 20 | int byte_order = 0; 21 | int cpu_family = 0; 22 | int cpu_type = 0; 23 | int no_of_cores = 0; 24 | int logical_cpu = 0; 25 | int physical_cpu = 0; 26 | uint64 cpu_frequency = 0; 27 | uint64 l1d_cache_bytes = 0; 28 | uint64 l1i_cache_bytes = 0; 29 | uint64 l2_cache_bytes = 0; 30 | uint64 l3_cache_bytes = 0; 31 | char model[MAXPGPATH]; 32 | char machine[MAXPGPATH]; 33 | char s_byte_order[MAXPGPATH]; 34 | char s_cpu_family[MAXPGPATH]; 35 | char s_cpu_type[MAXPGPATH]; 36 | size_t int_size = sizeof(int); 37 | size_t uint64_size = sizeof(uint64); 38 | size_t char_size = sizeof(model); 39 | int num_lst[2]; 40 | size_t len = 4; 41 | uint32_t count; 42 | 43 | memset(nulls, 0, sizeof(nulls)); 44 | memset(model, 0, MAXPGPATH); 45 | memset(machine, 0, MAXPGPATH); 46 | memset(s_byte_order, 0, MAXPGPATH); 47 | memset(s_cpu_family, 0, MAXPGPATH); 48 | memset(s_cpu_type, 0, MAXPGPATH); 49 | 50 | num_lst[0] = CTL_HW; num_lst[1] = HW_AVAILCPU; 51 | sysctl(num_lst, 2, &count, &len, NULL, 0); 52 | 53 | if(count < 1) 54 | { 55 | num_lst[1] = HW_NCPU; 56 | sysctl(num_lst, 2, &count, &len, NULL, 0); 57 | if(count < 1) 58 | count = 1; 59 | } 60 | 61 | no_of_cores = count; 62 | 63 | if (sysctlbyname("hw.byteorder", &byte_order, &int_size, 0, 0) == -1) 64 | nulls[Anum_cpu_byte_order] = true; 65 | 66 | if (sysctlbyname("hw.cpufamily", &cpu_family, &int_size, 0, 0) == -1) 67 | nulls[Anum_cpu_family] = true; 68 | 69 | if (sysctlbyname("hw.cputype", &cpu_type, &int_size, 0, 0) == -1) 70 | nulls[Anum_cpu_type] = true; 71 | 72 | if (sysctlbyname("hw.logicalcpu", &logical_cpu, &int_size, 0, 0) == -1) 73 | nulls[Anum_logical_processor] = true; 74 | 75 | if (sysctlbyname("hw.physicalcpu", &physical_cpu, &int_size, 0, 0) == -1) 76 | nulls[Anum_physical_processor] = true; 77 | 78 | if (sysctlbyname("hw.cpufrequency", &cpu_frequency, &uint64_size, 0, 0) == -1) 79 | nulls[Anum_cpu_clock_speed] = true; 80 | 81 | if (sysctlbyname("hw.l1dcachesize", &l1d_cache_bytes, &uint64_size, 0, 0) == -1) 82 | nulls[Anum_l1dcache_size] = true; 83 | 84 | if (sysctlbyname("hw.l1icachesize", &l1i_cache_bytes, &uint64_size, 0, 0) == -1) 85 | nulls[Anum_l1icache_size] = true; 86 | 87 | if (sysctlbyname("hw.l2cachesize", &l2_cache_bytes, &uint64_size, 0, 0) == -1) 88 | nulls[Anum_l2cache_size] = true; 89 | 90 | if (sysctlbyname("hw.l3cachesize", &l3_cache_bytes, &uint64_size, 0, 0) == -1) 91 | nulls[Anum_l3cache_size] = true; 92 | 93 | if (sysctlbyname("hw.model", model, &char_size, NULL, 0) == -1) 94 | nulls[Anum_model_name] = true; 95 | 96 | char_size = sizeof(machine); 97 | if (sysctlbyname("hw.machine", machine, &char_size, 0, 0) == -1) 98 | nulls[Anum_architecture] = true; 99 | 100 | snprintf(s_byte_order, MAXPGPATH, "%d", byte_order); 101 | snprintf(s_cpu_family, MAXPGPATH, "%d", cpu_family); 102 | snprintf(s_cpu_type, MAXPGPATH, "%d", cpu_type); 103 | 104 | nulls[Anum_cpu_vendor] = true; 105 | nulls[Anum_cpu_description] = true; 106 | nulls[Anum_processor_type] = true; 107 | 108 | values[Anum_no_of_cores] = Int32GetDatum(no_of_cores); 109 | values[Anum_cpu_byte_order] = CStringGetTextDatum(s_byte_order); 110 | values[Anum_cpu_family] = CStringGetTextDatum(s_cpu_family); 111 | values[Anum_cpu_type] = CStringGetTextDatum(s_cpu_type); 112 | values[Anum_logical_processor] = Int32GetDatum(logical_cpu); 113 | values[Anum_physical_processor] = Int32GetDatum(physical_cpu); 114 | values[Anum_cpu_clock_speed] = UInt64GetDatum(cpu_frequency); 115 | values[Anum_l1dcache_size] = Int32GetDatum((int)(l1d_cache_bytes/1024)); 116 | values[Anum_l1icache_size] = Int32GetDatum((int)(l1i_cache_bytes/1024)); 117 | values[Anum_l2cache_size] = Int32GetDatum((int)(l2_cache_bytes/1024)); 118 | values[Anum_l3cache_size] = Int32GetDatum((int)(l3_cache_bytes/1024)); 119 | values[Anum_model_name] = CStringGetTextDatum(model); 120 | values[Anum_architecture] = CStringGetTextDatum(machine); 121 | 122 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 123 | } 124 | -------------------------------------------------------------------------------- /darwin/cpu_memory_by_process.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * cpu_memory_by_process.c 3 | * CPU and memory usage of all processes 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | 23 | extern int get_process_list(struct kinfo_proc **proc_list, size_t *proc_count); 24 | extern uint64 find_cpu_times(void); 25 | void CreateCPUMemoryList(int sample); 26 | void findProcess(void); 27 | 28 | #define READ_PROCESS_CPU_USAGE_FIRST_SAMPLE 1 29 | #define READ_PROCESS_CPU_USAGE_SECOND_SAMPLE 2 30 | 31 | static long long unsigned int total_cpu_usage_1 = 0; 32 | static long long unsigned int total_cpu_usage_2 = 0; 33 | 34 | /* structure used to store the data for each process */ 35 | typedef struct node 36 | { 37 | long long unsigned int pid; 38 | long long unsigned int process_cpu_sample_1; 39 | long long unsigned int process_cpu_sample_2; 40 | long long unsigned int rss_memory; 41 | char name[MAXPGPATH]; 42 | int process_owned_by_user; 43 | struct node * next; 44 | } node_t; 45 | 46 | node_t *head = NULL; 47 | node_t *prev = NULL; 48 | node_t *iter = NULL; 49 | 50 | /* Function used to create the data structure for each process CPU and memory usage information */ 51 | void CreateCPUMemoryList(int sample) 52 | { 53 | struct kinfo_proc *proclist = NULL; 54 | struct kinfo_proc *org_proc_addr = NULL; 55 | size_t num_processes; 56 | size_t index; 57 | 58 | if (get_process_list(&proclist, &num_processes) != 0) 59 | return; 60 | 61 | // save the address of proclist so we can free it later 62 | org_proc_addr = proclist; 63 | for (index = 0; index < num_processes; index++) 64 | { 65 | pid_t pid; 66 | struct proc_taskinfo pti; 67 | int ret_val = 0; 68 | 69 | pid = (pid_t)proclist->kp_proc.p_pid; 70 | ret_val = proc_pidinfo(proclist->kp_proc.p_pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti)); 71 | if ((ret_val <= 0) || ((unsigned long)ret_val < sizeof(pti))) 72 | elog(DEBUG1, "proc_pidinfo[pid: %d] return value: [%d]", (int)pid, ret_val); 73 | 74 | if (sample == READ_PROCESS_CPU_USAGE_FIRST_SAMPLE) 75 | { 76 | iter = (node_t *) malloc(sizeof(node_t)); 77 | if (iter == NULL) 78 | { 79 | proclist++; 80 | continue; 81 | } 82 | 83 | memset(iter, 0x00, sizeof(node_t)); 84 | iter->pid = proclist->kp_proc.p_pid; 85 | memcpy(iter->name, proclist->kp_proc.p_comm, MAXPGPATH); 86 | if ((ret_val <= 0) || ((unsigned long)ret_val < sizeof(pti))) 87 | iter->process_owned_by_user = 0; 88 | else 89 | { 90 | iter->process_cpu_sample_1 = pti.pti_total_user + pti.pti_total_system; 91 | iter->rss_memory = pti.pti_resident_size; 92 | iter->process_owned_by_user = 1; 93 | } 94 | 95 | iter->next = NULL; 96 | if (head == NULL) 97 | head = iter; 98 | else 99 | prev->next = iter; 100 | prev = iter; 101 | } 102 | else 103 | { 104 | node_t * current = head; 105 | while (current != NULL) 106 | { 107 | if (current->pid == (int)pid) 108 | { 109 | if (!(ret_val <= 0) || ((unsigned long)ret_val < sizeof(pti))) 110 | current->process_cpu_sample_2 = pti.pti_total_user + pti.pti_total_system; 111 | break; 112 | } 113 | else 114 | current = current->next; 115 | } 116 | } 117 | 118 | proclist++; 119 | } 120 | 121 | free(org_proc_addr); 122 | } 123 | 124 | void ReadCPUMemoryByProcess(Tuplestorestate *tupstore, TupleDesc tupdesc) 125 | { 126 | Datum values[Natts_cpu_memory_info_by_process]; 127 | bool nulls[Natts_cpu_memory_info_by_process]; 128 | char command[MAXPGPATH]; 129 | int process_pid = 0; 130 | float4 cpu_usage = 0.0; 131 | float4 memory_usage = 0.0; 132 | int desc[2]; 133 | uint64 total_memory; 134 | uint64 page_size_bytes; 135 | int num_cpus = 0; 136 | size_t size_cpus = sizeof(num_cpus); 137 | size_t p_size = sizeof(page_size_bytes); 138 | long long unsigned int rss_memory; 139 | node_t *del_iter = NULL; 140 | node_t *current = NULL; 141 | 142 | memset(nulls, 0, sizeof(nulls)); 143 | memset(command, 0, MAXPGPATH); 144 | 145 | desc[0] = CTL_HW; 146 | desc[1] = HW_MEMSIZE; 147 | 148 | /* Find the total physical memory available with the system */ 149 | if (sysctl(desc, 2, &total_memory, &p_size, NULL, 0)) 150 | ereport(DEBUG1, (errmsg("Error while getting total memory information"))); 151 | 152 | /* Get the total number of CPUs */ 153 | if (sysctlbyname("hw.ncpu", &num_cpus, &size_cpus, 0, 0) == -1) 154 | ereport(DEBUG1, (errmsg("Error while getting total CPU cores"))); 155 | 156 | /* Get the page size */ 157 | if (sysctlbyname("hw.pagesize", &page_size_bytes, &p_size, 0, 0) == -1) 158 | ereport(DEBUG1, (errmsg("Error while getting page size information"))); 159 | 160 | total_cpu_usage_1 = find_cpu_times(); 161 | /* Read the first sample for cpu and memory usage by each process */ 162 | CreateCPUMemoryList(READ_PROCESS_CPU_USAGE_FIRST_SAMPLE); 163 | usleep(100000); 164 | /* Read the second sample for cpu and memory usage by each process */ 165 | total_cpu_usage_2 = find_cpu_times(); 166 | CreateCPUMemoryList(READ_PROCESS_CPU_USAGE_SECOND_SAMPLE); 167 | 168 | // Iterate through head and read all the informations */ 169 | current = head; 170 | 171 | // Process the CPU and memory information from linked list and free it once processed */ 172 | while (current != NULL) 173 | { 174 | process_pid = current->pid; 175 | memcpy(command, current->name, MAXPGPATH); 176 | if (current->process_owned_by_user) 177 | { 178 | float diff_sample = (float)(current->process_cpu_sample_2 - current->process_cpu_sample_1) / 1000000000.0; 179 | cpu_usage = (num_cpus) * (diff_sample) * 100 / (float) ((total_cpu_usage_2 - total_cpu_usage_1)/CLK_TCK); 180 | cpu_usage = (float)((int)(cpu_usage * 100 + 0.5))/100; 181 | rss_memory = current->rss_memory; 182 | memory_usage = (rss_memory/(float)total_memory)*100; 183 | memory_usage = (float)((int)(memory_usage * 100 + 0.5))/100; 184 | values[Anum_percent_cpu_usage] = Float4GetDatum(cpu_usage); 185 | values[Anum_percent_memory_usage] = Float4GetDatum(memory_usage); 186 | values[Anum_process_memory_bytes] = UInt64GetDatum((uint64)rss_memory); 187 | } 188 | else 189 | { 190 | nulls[Anum_percent_cpu_usage] = true; 191 | nulls[Anum_percent_memory_usage] = true; 192 | nulls[Anum_process_memory_bytes] = true; 193 | } 194 | 195 | values[Anum_process_pid] = Int32GetDatum(process_pid); 196 | values[Anum_process_name] = CStringGetTextDatum(command); 197 | 198 | nulls[Anum_process_running_since] = true; 199 | 200 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 201 | 202 | //reset the value again 203 | memset(command, 0, MAXPGPATH); 204 | process_pid = 0; 205 | cpu_usage = 0.0; 206 | memory_usage = 0.0; 207 | 208 | del_iter = current; 209 | current = current->next; 210 | if (del_iter != NULL) 211 | { 212 | free(del_iter); 213 | del_iter = NULL; 214 | } 215 | } 216 | 217 | head = NULL; 218 | prev = NULL; 219 | iter = NULL; 220 | } 221 | -------------------------------------------------------------------------------- /darwin/cpu_usage_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * cpu_usage_info.c 3 | * System CPU usage information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | struct cpu_stat 19 | { 20 | uint64 user; 21 | uint64 system; 22 | uint64 idle; 23 | uint64 nice; 24 | uint64 total; 25 | }; 26 | 27 | int cpu_stat_information(struct cpu_stat* cpu_stat); 28 | 29 | /* Function used to get CPU state information for each mode of operation */ 30 | int cpu_stat_information(struct cpu_stat* cpu_stat) 31 | { 32 | host_cpu_load_info_data_t cpu_load; 33 | mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT; 34 | kern_return_t ret = host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)&cpu_load, &count); 35 | if (ret != KERN_SUCCESS) 36 | { 37 | ereport(DEBUG1, (errmsg("[cpu_stat_information]: Error while getting host statistics information"))); 38 | return 1; 39 | } 40 | 41 | cpu_stat->user = cpu_load.cpu_ticks[CPU_STATE_USER]; 42 | cpu_stat->system = cpu_load.cpu_ticks[CPU_STATE_SYSTEM]; 43 | cpu_stat->idle = cpu_load.cpu_ticks[CPU_STATE_IDLE]; 44 | cpu_stat->nice = cpu_load.cpu_ticks[CPU_STATE_NICE]; 45 | cpu_stat->total = cpu_stat->user + cpu_stat->system + cpu_stat->idle + cpu_stat->nice; 46 | 47 | return 0; 48 | } 49 | 50 | void ReadCPUUsageStatistics(Tuplestorestate *tupstore, TupleDesc tupdesc) 51 | { 52 | Datum values[Natts_cpu_usage_stats]; 53 | bool nulls[Natts_cpu_usage_stats]; 54 | struct cpu_stat first_sample, second_sample; 55 | float4 total, user, system, idle, nice; 56 | 57 | memset(nulls, 0, sizeof(nulls)); 58 | 59 | /* Take the first sample regarding cpu usage statistics */ 60 | if (cpu_stat_information(&first_sample)) 61 | { 62 | ereport(DEBUG1, (errmsg("Error while getting CPU statistics information for the first sample"))); 63 | return; 64 | } 65 | 66 | /* sleep for the 100ms between 2 samples tp find cpu usage statistics */ 67 | usleep(100000); 68 | /* Take the second sample regarding cpu usage statistics */ 69 | if (cpu_stat_information(&second_sample)) 70 | { 71 | ereport(DEBUG1, (errmsg("Error while getting CPU statistics information for the second sample"))); 72 | return; 73 | } 74 | 75 | total = (float4)(second_sample.total - first_sample.total); 76 | user = (float4)(second_sample.user - first_sample.user) / total * 100; 77 | system = (float4)(second_sample.system - first_sample.system) / total * 100; 78 | idle = (float4)(second_sample.idle - first_sample.idle) / total * 100; 79 | nice = (float4)(second_sample.nice - first_sample.nice) / total * 100; 80 | 81 | values[Anum_usermode_normal_process] = Float4GetDatum(user); 82 | values[Anum_usermode_niced_process] = Float4GetDatum(nice); 83 | values[Anum_kernelmode_process] = Float4GetDatum(system); 84 | values[Anum_idle_mode] = Float4GetDatum(idle); 85 | 86 | nulls[Anum_io_completion] = true; 87 | nulls[Anum_servicing_irq] = true; 88 | nulls[Anum_servicing_softirq] = true; 89 | nulls[Anum_percent_user_time] = true; 90 | nulls[Anum_percent_processor_time] = true; 91 | nulls[Anum_percent_privileged_time] = true; 92 | nulls[Anum_percent_interrupt_time] = true; 93 | 94 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 95 | } 96 | -------------------------------------------------------------------------------- /darwin/disk_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * disk_info.c 3 | * System disk information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | /* This function is used to ignore the file system types */ 18 | bool ignoreFileSystemTypes(char *fs_mnt) 19 | { 20 | regex_t regex; 21 | int reg_return; 22 | bool ret_value = false; 23 | 24 | reg_return = regcomp(®ex, IGNORE_FILE_SYSTEM_TYPE_REGEX, REG_EXTENDED); 25 | if (reg_return) 26 | { 27 | ereport(DEBUG1, 28 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 29 | errmsg("Could not compile regex"))); 30 | return ret_value; 31 | } 32 | 33 | /* Execute regular expression */ 34 | reg_return = regexec(®ex, fs_mnt, 0, NULL, 0); 35 | if (!reg_return) 36 | ret_value = true; 37 | else if (reg_return == REG_NOMATCH) 38 | ret_value = false; 39 | else 40 | { 41 | ret_value = false; 42 | ereport(DEBUG1, 43 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 44 | errmsg("regex match failed"))); 45 | } 46 | 47 | /* Free memory allocated to the pattern buffer by regcomp() */ 48 | regfree(®ex); 49 | 50 | return ret_value; 51 | } 52 | 53 | /* This function is used to ignore the mount points */ 54 | bool ignoreMountPoints(char *fs_mnt) 55 | { 56 | regex_t regex; 57 | int reg_return; 58 | bool ret_value = false; 59 | 60 | reg_return = regcomp(®ex, IGNORE_MOUNT_POINTS_REGEX, REG_EXTENDED); 61 | if (reg_return) 62 | { 63 | ereport(DEBUG1, 64 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 65 | errmsg("Could not compile regex"))); 66 | return ret_value; 67 | } 68 | 69 | /* Execute regular expression */ 70 | reg_return = regexec(®ex, fs_mnt, 0, NULL, 0); 71 | if (!reg_return) 72 | ret_value = true; 73 | else if (reg_return == REG_NOMATCH) 74 | ret_value = false; 75 | else 76 | { 77 | ret_value = false; 78 | ereport(DEBUG1, 79 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 80 | errmsg("regex match failed"))); 81 | } 82 | 83 | /* Free memory allocated to the pattern buffer by regcomp() */ 84 | regfree(®ex); 85 | 86 | return ret_value; 87 | } 88 | 89 | void ReadDiskInformation(Tuplestorestate *tupstore, TupleDesc tupdesc) 90 | { 91 | Datum values[Natts_disk_info]; 92 | bool nulls[Natts_disk_info]; 93 | char file_system[MAXPGPATH]; 94 | char mount_point[MAXPGPATH]; 95 | char file_system_type[MAXPGPATH]; 96 | uint64 used_space_bytes = 0; 97 | uint64 total_space_bytes = 0; 98 | uint64 available_space_bytes = 0; 99 | uint64 total_inodes = 0; 100 | uint64 used_inodes = 0; 101 | uint64 free_inodes = 0; 102 | struct statfs *buf; 103 | int total_count = 0; 104 | int i = 0; 105 | 106 | memset(nulls, 0, sizeof(nulls)); 107 | memset(file_system, 0, MAXPGPATH); 108 | memset(mount_point, 0, MAXPGPATH); 109 | memset(file_system_type, 0, MAXPGPATH); 110 | 111 | total_count = getmntinfo(&buf, MNT_NOWAIT); 112 | for(i = 0; i < total_count; i++) 113 | { 114 | if (ignoreFileSystemTypes(buf[i].f_fstypename) || ignoreMountPoints(buf[i].f_mntonname)) 115 | continue; 116 | 117 | total_space_bytes = (uint64_t)(buf[i].f_blocks * buf[i].f_bsize); 118 | 119 | /* If total space of file system is zero, ignore that from list */ 120 | if (total_space_bytes == 0) 121 | continue; 122 | 123 | used_space_bytes = (uint64_t)((buf[i].f_blocks - buf[i].f_bfree) * buf[i].f_bsize); 124 | available_space_bytes = (uint64_t)(buf[i].f_bavail * buf[i].f_bsize); 125 | total_inodes = (uint64_t)buf[i].f_files; 126 | free_inodes = (uint64_t)buf[i].f_ffree; 127 | used_inodes = (uint64_t)(total_inodes - free_inodes); 128 | 129 | memcpy(file_system, buf[i].f_fstypename, strlen(buf[i].f_fstypename)); 130 | memcpy(mount_point, buf[i].f_mntonname, strlen(buf[i].f_mntonname)); 131 | memcpy(file_system_type, buf[i].f_mntfromname, strlen(buf[i].f_mntfromname)); 132 | 133 | /* not used for this platform so set to NULL */ 134 | nulls[Anum_disk_drive_letter] = true; 135 | nulls[Anum_disk_drive_type] = true; 136 | 137 | values[Anum_disk_file_system] = CStringGetTextDatum(file_system); 138 | values[Anum_disk_file_system_type] = CStringGetTextDatum(file_system_type); 139 | values[Anum_disk_mount_point] = CStringGetTextDatum(mount_point); 140 | values[Anum_disk_total_space] = UInt64GetDatum(total_space_bytes); 141 | values[Anum_disk_used_space] = UInt64GetDatum(used_space_bytes); 142 | values[Anum_disk_free_space] = UInt64GetDatum(available_space_bytes); 143 | values[Anum_disk_total_inodes] = UInt64GetDatum(total_inodes); 144 | values[Anum_disk_used_inodes] = UInt64GetDatum(used_inodes); 145 | values[Anum_disk_free_inodes] = UInt64GetDatum(free_inodes); 146 | 147 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 148 | 149 | //reset the value again 150 | memset(file_system, 0, MAXPGPATH); 151 | memset(mount_point, 0, MAXPGPATH); 152 | memset(file_system_type, 0, MAXPGPATH); 153 | used_space_bytes = 0; 154 | total_space_bytes = 0; 155 | available_space_bytes = 0; 156 | total_inodes = 0; 157 | used_inodes = 0; 158 | free_inodes = 0; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /darwin/io_analysis.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * io_analysis.c 3 | * System IO analysis information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | /* Here Size is defined in both postgres and Mac Foundation class 14 | so defined it here to avoid compilation error */ 15 | #define Size size_mac 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #undef Size 24 | 25 | // Both kIOMasterPortDefault or kIOMainPortDefault are synonyms for 0 26 | // so no dependency of specific mac os version. 27 | static const mach_port_t darwin_default_master_port = 0; 28 | 29 | /* Function used to get IO statistics of block devices */ 30 | void ReadIOAnalysisInformation(Tuplestorestate *tupstore, TupleDesc tupdesc) 31 | { 32 | Datum values[Natts_io_analysis_info]; 33 | bool nulls[Natts_io_analysis_info]; 34 | CFDictionaryRef disk_parent_dict; 35 | CFDictionaryRef disk_prop_dict; 36 | CFDictionaryRef disk_stats_dict; 37 | io_registry_entry_t parent_reg_ent; 38 | io_registry_entry_t disk_reg_ent; 39 | io_iterator_t disk_list_iter; 40 | 41 | memset(nulls, 0, sizeof(nulls)); 42 | 43 | // Get list of disks 44 | if (IOServiceGetMatchingServices(darwin_default_master_port, 45 | IOServiceMatching(kIOMediaClass), 46 | &disk_list_iter) != kIOReturnSuccess) 47 | { 48 | ereport(DEBUG1, (errmsg("Failed to get the list of the disks"))); 49 | return; 50 | } 51 | 52 | // Iterate over disks 53 | while ((disk_reg_ent = IOIteratorNext(disk_list_iter)) != 0) 54 | { 55 | disk_parent_dict = NULL; 56 | disk_prop_dict = NULL; 57 | disk_stats_dict = NULL; 58 | 59 | if (IORegistryEntryGetParentEntry(disk_reg_ent, 60 | kIOServicePlane, &parent_reg_ent) != kIOReturnSuccess) 61 | { 62 | ereport(DEBUG1, (errmsg("Failed to get the parent of the disk"))); 63 | IOObjectRelease(disk_reg_ent); 64 | IOObjectRelease (disk_list_iter); 65 | return; 66 | } 67 | 68 | if (IOObjectConformsTo(parent_reg_ent, "IOBlockStorageDriver")) 69 | { 70 | const int kMaxDiskNameSize = 64; 71 | char device_name[kMaxDiskNameSize]; 72 | CFStringRef disk_name_ref; 73 | CFNumberRef number; 74 | int64_t reads = 0; 75 | int64_t writes = 0; 76 | int64_t read_bytes = 0; 77 | int64_t write_bytes = 0; 78 | int64_t read_time_ns = 0; 79 | int64_t write_time_ns = 0; 80 | 81 | if (IORegistryEntryCreateCFProperties( 82 | disk_reg_ent, 83 | (CFMutableDictionaryRef *) &disk_parent_dict, 84 | kCFAllocatorDefault, 85 | kNilOptions) != kIOReturnSuccess) 86 | { 87 | ereport(DEBUG1, (errmsg("Failed to get the parent's disk properties"))); 88 | IOObjectRelease(disk_reg_ent); 89 | IOObjectRelease(parent_reg_ent); 90 | IOObjectRelease (disk_list_iter); 91 | return; 92 | } 93 | 94 | if (IORegistryEntryCreateCFProperties( 95 | parent_reg_ent, 96 | (CFMutableDictionaryRef *) &disk_prop_dict, 97 | kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess) 98 | { 99 | ereport(DEBUG1, (errmsg("Failed to get the disk properties"))); 100 | CFRelease(disk_parent_dict); 101 | IOObjectRelease(disk_reg_ent); 102 | IOObjectRelease(parent_reg_ent); 103 | IOObjectRelease (disk_list_iter); 104 | return; 105 | } 106 | 107 | disk_name_ref = (CFStringRef)CFDictionaryGetValue(disk_parent_dict, CFSTR(kIOBSDNameKey)); 108 | 109 | CFStringGetCString(disk_name_ref, 110 | device_name, 111 | kMaxDiskNameSize, 112 | CFStringGetSystemEncoding()); 113 | 114 | disk_stats_dict = (CFDictionaryRef)CFDictionaryGetValue( 115 | disk_prop_dict, CFSTR(kIOBlockStorageDriverStatisticsKey)); 116 | 117 | if (disk_stats_dict == NULL) 118 | { 119 | ereport(DEBUG1, (errmsg("Failed to get the disk stats"))); 120 | CFRelease(disk_parent_dict); 121 | IOObjectRelease(parent_reg_ent); 122 | CFRelease(disk_prop_dict); 123 | IOObjectRelease(disk_reg_ent); 124 | IOObjectRelease (disk_list_iter); 125 | return; 126 | } 127 | 128 | // Get disk reads/writes 129 | if ((number = (CFNumberRef)CFDictionaryGetValue( 130 | disk_stats_dict, 131 | CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) 132 | { 133 | CFNumberGetValue(number, kCFNumberSInt64Type, &reads); 134 | } 135 | if ((number = (CFNumberRef)CFDictionaryGetValue( 136 | disk_stats_dict, 137 | CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) 138 | { 139 | CFNumberGetValue(number, kCFNumberSInt64Type, &writes); 140 | } 141 | 142 | // Get disk bytes read/written 143 | if ((number = (CFNumberRef)CFDictionaryGetValue( 144 | disk_stats_dict, 145 | CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) 146 | { 147 | CFNumberGetValue(number, kCFNumberSInt64Type, &read_bytes); 148 | } 149 | if ((number = (CFNumberRef)CFDictionaryGetValue( 150 | disk_stats_dict, 151 | CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) 152 | { 153 | CFNumberGetValue(number, kCFNumberSInt64Type, &write_bytes); 154 | } 155 | 156 | // Get disk time spent reading/writing (nanoseconds) 157 | if ((number = (CFNumberRef)CFDictionaryGetValue( 158 | disk_stats_dict, 159 | CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey)))) 160 | { 161 | CFNumberGetValue(number, kCFNumberSInt64Type, &read_time_ns); 162 | } 163 | if ((number = (CFNumberRef)CFDictionaryGetValue( 164 | disk_stats_dict, 165 | CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey)))) 166 | { 167 | CFNumberGetValue(number, kCFNumberSInt64Type, &write_time_ns); 168 | } 169 | 170 | /* convert nano second to milli second */ 171 | read_time_ns = (int64_t)round(read_time_ns/1000000); 172 | write_time_ns = (int64_t)round(write_time_ns/1000000); 173 | 174 | values[Anum_device_name] = CStringGetTextDatum(device_name); 175 | values[Anum_total_read] = UInt64GetDatum(reads); 176 | values[Anum_total_write] = UInt64GetDatum(writes); 177 | values[Anum_read_bytes] = UInt64GetDatum(read_bytes); 178 | values[Anum_write_bytes] = UInt64GetDatum(write_bytes); 179 | values[Anum_read_time_ms] = UInt64GetDatum(read_time_ns); 180 | values[Anum_write_time_ms] = UInt64GetDatum(write_time_ns); 181 | 182 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 183 | 184 | CFRelease(disk_parent_dict); 185 | IOObjectRelease(parent_reg_ent); 186 | CFRelease(disk_prop_dict); 187 | IOObjectRelease(disk_reg_ent); 188 | } 189 | 190 | } 191 | 192 | IOObjectRelease (disk_list_iter); 193 | } 194 | -------------------------------------------------------------------------------- /darwin/load_avg.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * load_avg.c 3 | * System load average information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #include "postgres.h" 14 | #include "system_stats.h" 15 | 16 | void ReadLoadAvgInformations(Tuplestorestate *tupstore, TupleDesc tupdesc) 17 | { 18 | Datum values[Natts_load_avg_info]; 19 | bool nulls[Natts_load_avg_info]; 20 | struct loadavg load; 21 | size_t size = sizeof(load); 22 | float4 load_avg_one_minute = 0; 23 | float4 load_avg_five_minutes = 0; 24 | float4 load_avg_fifteen_minutes = 0; 25 | 26 | memset(nulls, 0, sizeof(nulls)); 27 | 28 | /* Read the load average from kernel */ 29 | if (sysctlbyname("vm.loadavg", &load, &size, 0, 0) == -1) 30 | { 31 | ereport(DEBUG1, (errmsg("Error while getting loadavg information from kernel"))); 32 | return; 33 | } 34 | 35 | load_avg_one_minute = (float4)load.ldavg[0]/load.fscale; 36 | load_avg_five_minutes = (float4)load.ldavg[1]/load.fscale; 37 | load_avg_fifteen_minutes = (float4)load.ldavg[2]/load.fscale; 38 | 39 | values[Anum_load_avg_one_minute] = Float4GetDatum(load_avg_one_minute); 40 | values[Anum_load_avg_five_minutes] = Float4GetDatum(load_avg_five_minutes); 41 | values[Anum_load_avg_fifteen_minutes] = Float4GetDatum(load_avg_fifteen_minutes); 42 | nulls[Anum_load_avg_ten_minutes] = true; 43 | 44 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 45 | } 46 | -------------------------------------------------------------------------------- /darwin/memory_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * memory_info.c 3 | * System memory information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | #include "postgres.h" 10 | #include "system_stats.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | void ReadMemoryInformation(Tuplestorestate *tupstore, TupleDesc tupdesc) 20 | { 21 | Datum values[Natts_memory_info]; 22 | bool nulls[Natts_memory_info]; 23 | uint64 total_memory_bytes = 0; 24 | uint64 free_memory_bytes = 0; 25 | uint64 used_memory_bytes = 0; 26 | vm_statistics64_data_t vm_stat; 27 | kern_return_t ret; 28 | mach_msg_type_number_t count = sizeof(vm_stat) / sizeof(int); 29 | size_t size; 30 | struct xsw_usage swap_mem; 31 | int desc[2]; 32 | uint64_t total; 33 | size_t len = sizeof(total); 34 | int pagesize = getpagesize(); 35 | mach_port_t mport; 36 | 37 | memset(nulls, 0, sizeof(nulls)); 38 | 39 | // Set the read parameter from kernel as virtual memory total size 40 | desc[0] = CTL_HW; 41 | desc[1] = HW_MEMSIZE; 42 | 43 | if (sysctl(desc, 2, &total_memory_bytes, &len, NULL, 0)) 44 | { 45 | ereport(DEBUG1, (errmsg("Error while getting total memory information"))); 46 | return; 47 | } 48 | 49 | mport = mach_host_self(); 50 | 51 | /* Read the host memory statistics */ 52 | ret = host_statistics(mport, HOST_VM_INFO, (host_info_t)&vm_stat, &count); 53 | if (ret != KERN_SUCCESS) { 54 | ereport(DEBUG1, (errmsg("host_statistics failed to get the host information"))); 55 | } 56 | 57 | mach_port_deallocate(mach_task_self(), mport); 58 | 59 | free_memory_bytes = (vm_stat.inactive_count + vm_stat.free_count) * pagesize; 60 | used_memory_bytes = total_memory_bytes - free_memory_bytes; 61 | 62 | /* Set the read parameter for swap memory usage */ 63 | desc[0] = CTL_VM; 64 | desc[1] = VM_SWAPUSAGE; 65 | size = sizeof(swap_mem); 66 | 67 | /* Read the swap memory usage */ 68 | if (sysctl(desc, 2, &swap_mem, &size, NULL, 0) == -1) 69 | { 70 | ereport(DEBUG1, (errmsg("Error while getting swap memory information"))); 71 | } 72 | 73 | values[Anum_total_memory] = UInt64GetDatum(total_memory_bytes); 74 | values[Anum_used_memory] = UInt64GetDatum(used_memory_bytes); 75 | values[Anum_free_memory] = UInt64GetDatum(free_memory_bytes); 76 | values[Anum_swap_total_memory] = UInt64GetDatum(swap_mem.xsu_total); 77 | values[Anum_swap_used_memory] = UInt64GetDatum(swap_mem.xsu_used); 78 | values[Anum_swap_free_memory] = UInt64GetDatum(swap_mem.xsu_avail); 79 | nulls[Anum_total_cache_memory] = true; 80 | nulls[Anum_kernel_total_memory] = true; 81 | nulls[Anum_kernel_paged_memory] = true; 82 | nulls[Anum_kernel_nonpaged_memory] = true; 83 | nulls[Anum_total_page_file] = true; 84 | nulls[Anum_avail_page_file] = true; 85 | 86 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 87 | } 88 | -------------------------------------------------------------------------------- /darwin/network_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * network_info.c 3 | * System network information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | void ReadNetworkInformations(Tuplestorestate *tupstore, TupleDesc tupdesc) 31 | { 32 | Datum values[Natts_network_info]; 33 | bool nulls[Natts_network_info]; 34 | char interface_name[MAXPGPATH]; 35 | char ipv4_address[MAXPGPATH]; 36 | uint64 speed_mbps = 0; 37 | uint64 tx_bytes = 0; 38 | uint64 tx_packets = 0; 39 | uint64 tx_errors = 0; 40 | uint64 tx_dropped = 0; 41 | uint64 rx_bytes = 0; 42 | uint64 rx_packets = 0; 43 | uint64 rx_errors = 0; 44 | uint64 rx_dropped = 0; 45 | 46 | // First find out interface and ip address of that interface 47 | struct ifaddrs *ifaddr; 48 | struct ifaddrs *ifa; 49 | int ret_val; 50 | char host[MAXPGPATH]; 51 | 52 | // networking subsystem initialization 53 | char *buf = NULL, *limit, *next_ptr; 54 | struct if_msghdr *ifm; 55 | size_t len; 56 | int desc[6]; 57 | desc[0] = CTL_NET; 58 | desc[1] = PF_ROUTE; 59 | desc[2] = 0; 60 | desc[3] = 0; 61 | desc[4] = NET_RT_IFLIST2; 62 | desc[5] = 0; 63 | 64 | memset(nulls, 0, sizeof(nulls)); 65 | memset(interface_name, 0, MAXPGPATH); 66 | memset(ipv4_address, 0, MAXPGPATH); 67 | memset(host, 0, MAXPGPATH); 68 | 69 | if (sysctl(desc, 6, NULL, &len, NULL, 0) < 0) 70 | { 71 | ereport(DEBUG1, 72 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 73 | errmsg("Failed to get networking subsystem parameters"))); 74 | return; 75 | } 76 | 77 | buf = malloc(len); 78 | if (buf == NULL) 79 | { 80 | ereport(DEBUG1, (errmsg("Failed to allocate the memory"))); 81 | return; 82 | } 83 | 84 | if (sysctl(desc, 6, buf, &len, NULL, 0) < 0) 85 | { 86 | ereport(DEBUG1, 87 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 88 | errmsg("Failed to get networking subsystem parameters"))); 89 | if (buf) 90 | free(buf); 91 | return; 92 | } 93 | 94 | limit = buf + len; 95 | 96 | /* Below function is used to creates a linked list of structures describing 97 | * the network interfaces of the local system 98 | */ 99 | if (getifaddrs(&ifaddr) == -1) 100 | { 101 | ereport(DEBUG1, 102 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 103 | errmsg("Failed to get network interface"))); 104 | if (buf) 105 | free(buf); 106 | return; 107 | } 108 | 109 | for (next_ptr = buf; next_ptr < limit;) 110 | { 111 | ifm = (struct if_msghdr *)next_ptr; 112 | next_ptr += ifm->ifm_msglen; 113 | 114 | if (ifm->ifm_type == RTM_IFINFO2) 115 | { 116 | struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm; 117 | struct sockaddr_dl *sdl = (struct sockaddr_dl *)(if2m + 1); 118 | 119 | strncpy(interface_name, sdl->sdl_data, sdl->sdl_nlen); 120 | interface_name[sdl->sdl_nlen] = 0; 121 | 122 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) 123 | { 124 | if (ifa->ifa_addr == NULL) 125 | continue; 126 | 127 | ret_val = getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); 128 | 129 | if((strcmp(ifa->ifa_name, interface_name)==0) && (ifa->ifa_addr->sa_family==AF_INET)) 130 | { 131 | if (ret_val != 0) 132 | { 133 | ereport(ERROR, 134 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 135 | errmsg("getnameinfo() failed: %s", gai_strerror(ret_val)))); 136 | nulls[Anum_net_ipv4_address] = true; 137 | } 138 | 139 | memcpy(ipv4_address, host, MAXPGPATH); 140 | 141 | // Assign the values 142 | tx_bytes = (uint64)if2m->ifm_data.ifi_obytes; 143 | tx_packets = (uint64)if2m->ifm_data.ifi_opackets; 144 | tx_errors = (uint64)if2m->ifm_data.ifi_oerrors; 145 | tx_dropped = (uint64)0; 146 | speed_mbps = (uint64)0; 147 | rx_bytes = (uint64)if2m->ifm_data.ifi_ibytes; 148 | rx_packets = (uint64)if2m->ifm_data.ifi_ipackets; 149 | rx_errors = (uint64)if2m->ifm_data.ifi_ierrors; 150 | rx_dropped = (uint64)if2m->ifm_data.ifi_iqdrops; 151 | 152 | values[Anum_net_interface_name] = CStringGetTextDatum(interface_name); 153 | values[Anum_net_ipv4_address] = CStringGetTextDatum(ipv4_address); 154 | values[Anum_net_speed_mbps] = UInt64GetDatum(speed_mbps); 155 | values[Anum_net_tx_bytes] = UInt64GetDatum(tx_bytes); 156 | values[Anum_net_tx_packets] = UInt64GetDatum(tx_packets); 157 | values[Anum_net_tx_errors] = UInt64GetDatum(tx_errors); 158 | values[Anum_net_tx_dropped] = UInt64GetDatum(tx_dropped); 159 | values[Anum_net_rx_bytes] = UInt64GetDatum(rx_bytes); 160 | values[Anum_net_rx_packets] = UInt64GetDatum(rx_packets); 161 | values[Anum_net_rx_errors] = UInt64GetDatum(rx_errors); 162 | values[Anum_net_rx_dropped] = UInt64GetDatum(rx_dropped); 163 | 164 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 165 | 166 | //reset the value again 167 | memset(interface_name, 0, MAXPGPATH); 168 | memset(ipv4_address, 0, MAXPGPATH); 169 | speed_mbps = 0; 170 | tx_bytes = 0; 171 | tx_packets = 0; 172 | tx_errors = 0; 173 | tx_dropped = 0; 174 | rx_bytes = 0; 175 | rx_packets = 0; 176 | rx_errors = 0; 177 | rx_dropped = 0; 178 | } 179 | } 180 | } 181 | else 182 | continue; 183 | } 184 | 185 | freeifaddrs(ifaddr); 186 | free(buf); 187 | } 188 | -------------------------------------------------------------------------------- /darwin/os_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * os_info.c 3 | * Operating system information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | extern int get_process_list(struct kinfo_proc **proc_list, size_t *proc_count); 23 | 24 | void ReadOSInformations(Tuplestorestate *tupstore, TupleDesc tupdesc) 25 | { 26 | struct utsname uts; 27 | Datum values[Natts_os_info]; 28 | bool nulls[Natts_os_info]; 29 | char host_name[MAXPGPATH]; 30 | char domain_name[MAXPGPATH]; 31 | char os_name[MAXPGPATH]; 32 | char os_version_level[MAXPGPATH]; 33 | char architecture[MAXPGPATH]; 34 | int ret_val; 35 | size_t num_processes = 0; 36 | struct kinfo_proc *proc_list = NULL; 37 | int os_process_count = 0; 38 | struct timespec uptime; 39 | 40 | memset(nulls, 0, sizeof(nulls)); 41 | memset(host_name, 0, MAXPGPATH); 42 | memset(domain_name, 0, MAXPGPATH); 43 | memset(os_name, 0, MAXPGPATH); 44 | memset(architecture, 0, MAXPGPATH); 45 | memset(os_version_level, 0, MAXPGPATH); 46 | 47 | if (0 != clock_gettime(CLOCK_MONOTONIC_RAW, &uptime)) 48 | nulls[Anum_os_up_since_seconds] = true; 49 | 50 | if (get_process_list(&proc_list, &num_processes) != 0) 51 | { 52 | ereport(DEBUG1, (errmsg("Error while getting process information list from proc"))); 53 | return; 54 | } 55 | 56 | os_process_count = (int)num_processes; 57 | 58 | ret_val = uname(&uts); 59 | /* if it returns not zero means it fails so set null values */ 60 | if (ret_val != 0) 61 | { 62 | nulls[Anum_os_name] = true; 63 | nulls[Anum_os_version] = true; 64 | nulls[Anum_os_architecture] = true; 65 | } 66 | else 67 | { 68 | memcpy(os_name, uts.sysname, strlen(uts.sysname)); 69 | memcpy(os_version_level, uts.version, strlen(uts.version)); 70 | memcpy(architecture, uts.machine, strlen(uts.machine)); 71 | } 72 | 73 | /* Function used to get the host name of the system */ 74 | if (gethostname(host_name, sizeof(host_name)) != 0) 75 | ereport(DEBUG1, 76 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 77 | errmsg("error while getting host name"))); 78 | 79 | /* Function used to get the domain name of the system */ 80 | if (getdomainname(domain_name, sizeof(domain_name)) != 0) 81 | ereport(DEBUG1, 82 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 83 | errmsg("error while getting domain name"))); 84 | 85 | /*If hostname or domain name is empty, set the value to NULL */ 86 | if (strlen(host_name) == 0) 87 | nulls[Anum_host_name] = true; 88 | if (strlen(domain_name) == 0) 89 | nulls[Anum_domain_name] = true; 90 | 91 | values[Anum_host_name] = CStringGetTextDatum(host_name); 92 | values[Anum_domain_name] = CStringGetTextDatum(domain_name); 93 | values[Anum_os_name] = CStringGetTextDatum(os_name); 94 | values[Anum_os_version] = CStringGetTextDatum(os_version_level); 95 | values[Anum_os_architecture] = CStringGetTextDatum(architecture); 96 | values[Anum_os_process_count] = Int32GetDatum(os_process_count); 97 | values[Anum_os_up_since_seconds] = Int32GetDatum((int)uptime.tv_sec); 98 | 99 | nulls[Anum_os_handle_count] = true; 100 | nulls[Anum_os_thread_count] = true; 101 | nulls[Anum_os_boot_time] = true; 102 | 103 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 104 | } 105 | -------------------------------------------------------------------------------- /darwin/process_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * process_info.c 3 | * System process information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | 16 | extern int get_process_list(struct kinfo_proc **proc_list, size_t *proc_count); 17 | 18 | void ReadProcessInformations(Tuplestorestate *tupstore, TupleDesc tupdesc) 19 | { 20 | size_t num_processes = 0; 21 | int total_processes = 0; 22 | int running_processes = 0; 23 | int sleeping_processes = 0; 24 | int stopped_processes = 0; 25 | int zombie_processes = 0; 26 | struct kinfo_proc *proc_list = NULL; 27 | struct kinfo_proc *proc_list_addr = NULL; 28 | size_t index; 29 | Datum values[Natts_process_info]; 30 | bool nulls[Natts_process_info]; 31 | 32 | memset(nulls, 0, sizeof(nulls)); 33 | 34 | if (get_process_list(&proc_list, &num_processes) != 0) 35 | { 36 | ereport(DEBUG1, (errmsg("Error while getting process information list from proc"))); 37 | return; 38 | } 39 | 40 | total_processes = (int)num_processes; 41 | 42 | /* Save the allocated buffer pointer so that it can be freed at later */ 43 | proc_list_addr = proc_list; 44 | 45 | /* Iterate total processes to find its status */ 46 | for (index = 0; index < total_processes; index++) 47 | { 48 | if (proc_list->kp_proc.p_pid > 0 && (int)proc_list->kp_proc.p_stat == SRUN) 49 | running_processes++; 50 | if (proc_list->kp_proc.p_pid > 0 && (int)proc_list->kp_proc.p_stat == SSLEEP) 51 | sleeping_processes++; 52 | if (proc_list->kp_proc.p_pid > 0 && (int)proc_list->kp_proc.p_stat == SSTOP) 53 | stopped_processes++; 54 | if (proc_list->kp_proc.p_pid > 0 && (int)proc_list->kp_proc.p_stat == SZOMB) 55 | zombie_processes++; 56 | 57 | proc_list++; 58 | } 59 | 60 | free(proc_list_addr); 61 | 62 | values[Anum_no_of_total_processes] = Int32GetDatum(total_processes); 63 | values[Anum_no_of_running_processes] = Int32GetDatum(running_processes); 64 | values[Anum_no_of_sleeping_processes] = Int32GetDatum(sleeping_processes); 65 | values[Anum_no_of_stopped_processes] = Int32GetDatum(stopped_processes); 66 | values[Anum_no_of_zombie_processes] = Int32GetDatum(zombie_processes); 67 | 68 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 69 | } 70 | -------------------------------------------------------------------------------- /darwin/system_stats_utils.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * system_stats_utils.c 3 | * Defined required utility functions to fetch 4 | * system statistics information 5 | * 6 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 7 | * 8 | *------------------------------------------------------------------------ 9 | */ 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | int get_process_list(struct kinfo_proc **proc_list, size_t *proc_count); 21 | 22 | uint64 find_cpu_times(void); 23 | 24 | /* Below function is used to get cpu times for all the cpu states */ 25 | uint64 find_cpu_times() 26 | { 27 | mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT; 28 | kern_return_t error; 29 | host_cpu_load_info_data_t r_load; 30 | uint64 total_time; 31 | 32 | mach_port_t host_port = mach_host_self(); 33 | error = host_statistics(host_port, HOST_CPU_LOAD_INFO, (host_info_t)&r_load, &count); 34 | 35 | if (error != KERN_SUCCESS) 36 | { 37 | ereport(DEBUG1, (errmsg("host_statistics syscall failed: %s", mach_error_string(error)))); 38 | return (uint64)0; 39 | } 40 | 41 | mach_port_deallocate(mach_task_self(), host_port); 42 | 43 | total_time = r_load.cpu_ticks[CPU_STATE_USER] + r_load.cpu_ticks[CPU_STATE_NICE] + 44 | r_load.cpu_ticks[CPU_STATE_SYSTEM] + r_load.cpu_ticks[CPU_STATE_IDLE]; 45 | 46 | return total_time; 47 | } 48 | 49 | /* Below function is used to get all the process information and their status */ 50 | int get_process_list(struct kinfo_proc **proc_list, size_t *proc_count) 51 | { 52 | int mib_desc[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL }; 53 | size_t size, new_size; 54 | void *proc_list_ptr; 55 | 56 | *proc_count = 0; 57 | 58 | size = 0; 59 | if (sysctl((int *)mib_desc, 3, NULL, &size, NULL, 0) == -1) 60 | { 61 | ereport(DEBUG1, (errmsg("Failed to get process informations"))); 62 | return 1; 63 | } 64 | 65 | new_size = size + (size >> 3); 66 | if (new_size > size) 67 | { 68 | proc_list_ptr = malloc(new_size); 69 | if (proc_list_ptr == NULL) 70 | proc_list_ptr = malloc(size); 71 | else 72 | size = new_size; 73 | } 74 | else 75 | proc_list_ptr = malloc(size); 76 | 77 | if (proc_list_ptr == NULL) 78 | { 79 | ereport(DEBUG1, (errmsg("Failed to allocate the memory"))); 80 | return 1; 81 | } 82 | 83 | if (sysctl((int *)mib_desc, 3, proc_list_ptr, &size, NULL, 0) == -1) 84 | { 85 | if (proc_list_ptr) 86 | free(proc_list_ptr); 87 | ereport(DEBUG1, (errmsg("Failed to get process informations"))); 88 | return 1; 89 | } 90 | else 91 | { 92 | *proc_list = (struct kinfo_proc *)proc_list_ptr; 93 | *proc_count = size / sizeof(struct kinfo_proc); 94 | if (proc_count <= 0) 95 | { 96 | if (proc_list_ptr) 97 | free(proc_list_ptr); 98 | ereport(DEBUG1, (errmsg("Process count is zero"))); 99 | return 1; 100 | } 101 | 102 | /* return with success as it got process information */ 103 | return 0; 104 | } 105 | 106 | if (proc_list_ptr) 107 | free(proc_list_ptr); 108 | 109 | return 1; 110 | } 111 | -------------------------------------------------------------------------------- /linux/cpu_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * cpu_info.c 3 | * System CPU information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | #include 13 | 14 | #define L1D_CACHE_FILE_PATH "/sys/devices/system/cpu/cpu0/cache/index0/size" 15 | #define L1I_CACHE_FILE_PATH "/sys/devices/system/cpu/cpu0/cache/index1/size" 16 | #define L2_CACHE_FILE_PATH "/sys/devices/system/cpu/cpu0/cache/index2/size" 17 | #define L3_CACHE_FILE_PATH "/sys/devices/system/cpu/cpu0/cache/index3/size" 18 | 19 | int read_cpu_cache_size(const char *path); 20 | void ReadCPUInformation(Tuplestorestate *tupstore, TupleDesc tupdesc); 21 | 22 | int read_cpu_cache_size(const char *path) 23 | { 24 | FILE *fp; 25 | char *line_buf = NULL; 26 | size_t line_buf_size = 0; 27 | ssize_t line_size; 28 | int cache_size = 0; 29 | 30 | fp = fopen(path, "r"); 31 | if (!fp) 32 | { 33 | ereport(DEBUG1, (errmsg("can not open file{%s) for reading", L1D_CACHE_FILE_PATH))); 34 | cache_size = 0; 35 | } 36 | else 37 | { 38 | /* Get the first line of the file. */ 39 | line_size = getline(&line_buf, &line_buf_size, fp); 40 | 41 | /* Loop through until we are done with the file. */ 42 | if (line_size >= 0) 43 | { 44 | int len; 45 | size_t index; 46 | len = strlen(line_buf); 47 | for(index = 0; index < len; index++) 48 | { 49 | if( !isdigit(line_buf[index])) 50 | { 51 | line_buf[index] = '\0'; 52 | break; 53 | } 54 | } 55 | } 56 | 57 | cache_size = atoi(line_buf); 58 | 59 | if (line_buf != NULL) 60 | { 61 | free(line_buf); 62 | line_buf = NULL; 63 | } 64 | 65 | fclose(fp); 66 | } 67 | 68 | return cache_size; 69 | } 70 | 71 | void ReadCPUInformation(Tuplestorestate *tupstore, TupleDesc tupdesc) 72 | { 73 | struct utsname uts; 74 | char *found; 75 | FILE *cpu_info_file; 76 | Datum values[Natts_cpu_info]; 77 | bool nulls[Natts_cpu_info]; 78 | char vendor_id[MAXPGPATH]; 79 | char cpu_family[MAXPGPATH]; 80 | char cpu_desc[MAXPGPATH]; 81 | char model[MAXPGPATH]; 82 | char model_name[MAXPGPATH]; 83 | char cpu_mhz[MAXPGPATH]; 84 | char architecture[MAXPGPATH]; 85 | char *line_buf = NULL; 86 | size_t line_buf_size = 0; 87 | ssize_t line_size; 88 | bool model_found = false; 89 | int ret_val; 90 | int physical_processor = 0; 91 | int logical_processor = 0; 92 | int l1dcache_size_kb = 0; 93 | int l1icache_size_kb = 0; 94 | int l2cache_size_kb = 0; 95 | int l3cache_size_kb = 0; 96 | int cpu_cores = 0; 97 | float cpu_hz; 98 | uint64_t cpu_freq; 99 | 100 | memset(nulls, 0, sizeof(nulls)); 101 | memset(vendor_id, 0, MAXPGPATH); 102 | memset(cpu_family, 0, MAXPGPATH); 103 | memset(model, 0, MAXPGPATH); 104 | memset(model_name, 0, MAXPGPATH); 105 | memset(cpu_mhz, 0, MAXPGPATH); 106 | memset(architecture, 0, MAXPGPATH); 107 | memset(cpu_desc, 0, MAXPGPATH); 108 | 109 | l1dcache_size_kb = read_cpu_cache_size(L1D_CACHE_FILE_PATH); 110 | l1icache_size_kb = read_cpu_cache_size(L1I_CACHE_FILE_PATH); 111 | l2cache_size_kb = read_cpu_cache_size(L2_CACHE_FILE_PATH); 112 | l3cache_size_kb = read_cpu_cache_size(L3_CACHE_FILE_PATH); 113 | 114 | ret_val = uname(&uts); 115 | /* if it returns not zero means it fails so set null values */ 116 | if (ret_val != 0) 117 | nulls[Anum_architecture] = true; 118 | else 119 | memcpy(architecture, uts.machine, strlen(uts.machine)); 120 | 121 | cpu_info_file = fopen(CPU_INFO_FILE_NAME, "r"); 122 | 123 | if (!cpu_info_file) 124 | { 125 | char cpu_info_file_name[MAXPGPATH]; 126 | snprintf(cpu_info_file_name, MAXPGPATH, "%s", CPU_INFO_FILE_NAME); 127 | 128 | ereport(DEBUG1, 129 | (errcode_for_file_access(), 130 | errmsg("can not open file %s for reading cpu information", 131 | cpu_info_file_name))); 132 | return; 133 | } 134 | else 135 | { 136 | /* Get the first line of the file. */ 137 | line_size = getline(&line_buf, &line_buf_size, cpu_info_file); 138 | 139 | /* Loop through until we are done with the file. */ 140 | while (line_size >= 0) 141 | { 142 | if (strlen(line_buf) > 0) 143 | line_buf = trimStr(line_buf); 144 | 145 | if (!IS_EMPTY_STR(line_buf) && (strlen(line_buf) > 0)) 146 | { 147 | if (strlen(line_buf) > 0) 148 | { 149 | found = strstr(line_buf, ":"); 150 | if (strlen(found) > 0) 151 | { 152 | found = trimStr((found+1)); 153 | 154 | if (strstr(line_buf, "vendor_id") != NULL) 155 | memcpy(vendor_id, found, strlen(found)); 156 | if (strstr(line_buf, "cpu family") != NULL) 157 | memcpy(cpu_family, found, strlen(found)); 158 | if (strstr(line_buf, "model") != NULL && !model_found) 159 | { 160 | memcpy(model, found, strlen(found)); 161 | model_found = true; 162 | } 163 | if (strstr(line_buf, "model name") != NULL) 164 | memcpy(model_name, found, strlen(found)); 165 | if (strstr(line_buf, "cpu MHz") != NULL) 166 | { 167 | physical_processor++; 168 | memcpy(cpu_mhz, found, strlen(found)); 169 | } 170 | if (strstr(line_buf, "cpu cores") != NULL) 171 | cpu_cores = atoi(found); 172 | } 173 | } 174 | 175 | /* Free the allocated line buffer */ 176 | if (line_buf != NULL) 177 | { 178 | free(line_buf); 179 | line_buf = NULL; 180 | } 181 | } 182 | 183 | /* Get the next line */ 184 | line_size = getline(&line_buf, &line_buf_size, cpu_info_file); 185 | } 186 | 187 | /* Free the allocated line buffer */ 188 | if (line_buf != NULL) 189 | { 190 | free(line_buf); 191 | line_buf = NULL; 192 | } 193 | 194 | fclose(cpu_info_file); 195 | 196 | if (physical_processor) 197 | { 198 | snprintf(cpu_desc, MAXPGPATH, "%s model %s family %s", vendor_id, model, cpu_family); 199 | /* convert CPU frequency from MHz to Hz */ 200 | cpu_hz = atof(cpu_mhz); 201 | cpu_freq = (cpu_hz * 1000000); 202 | 203 | values[Anum_cpu_vendor] = CStringGetTextDatum(vendor_id); 204 | values[Anum_cpu_description] = CStringGetTextDatum(cpu_desc); 205 | values[Anum_model_name] = CStringGetTextDatum(model_name); 206 | values[Anum_logical_processor] = Int32GetDatum(logical_processor); 207 | values[Anum_physical_processor] = Int32GetDatum(physical_processor); 208 | values[Anum_no_of_cores] = Int32GetDatum(cpu_cores); 209 | values[Anum_architecture] = CStringGetTextDatum(architecture); 210 | values[Anum_cpu_clock_speed] = UInt64GetDatum(cpu_freq); 211 | values[Anum_l1dcache_size] = Int32GetDatum(l1dcache_size_kb); 212 | values[Anum_l1icache_size] = Int32GetDatum(l1icache_size_kb); 213 | values[Anum_l2cache_size] = Int32GetDatum(l2cache_size_kb); 214 | values[Anum_l3cache_size] = Int32GetDatum(l3cache_size_kb); 215 | 216 | nulls[Anum_processor_type] = true; 217 | nulls[Anum_cpu_type] = true; 218 | nulls[Anum_cpu_family] = true; 219 | nulls[Anum_cpu_byte_order] = true; 220 | 221 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /linux/cpu_usage_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * cpu_usage_info.c 3 | * System CPU usage information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | 15 | void ReadCPUUsageStatistics(Tuplestorestate *tupstore, TupleDesc tupdesc); 16 | 17 | struct cpu_stat 18 | { 19 | long long int usermode_normal_process; 20 | long long int usermode_niced_process; 21 | long long int kernelmode_process; 22 | long long int idle_mode; 23 | long long int io_completion; 24 | long long int servicing_irq; 25 | long long int servicing_softirq; 26 | }; 27 | 28 | void cpu_stat_information(struct cpu_stat* cpu_stat); 29 | /* Function used to get CPU state information for each mode of operation */ 30 | void cpu_stat_information(struct cpu_stat* cpu_stat) 31 | { 32 | FILE *cpu_stats_file; 33 | char *line_buf = NULL; 34 | size_t line_buf_size = 0; 35 | ssize_t line_size; 36 | long long int usermode_normal_process = 0; 37 | long long int usermode_niced_process = 0; 38 | long long int kernelmode_process = 0; 39 | long long int idle_mode = 0; 40 | long long int io_completion = 0; 41 | long long int servicing_irq = 0; 42 | long long int servicing_softirq = 0; 43 | const char *scan_fmt = "%*s %llu %llu %llu %llu %llu %llu %llu"; 44 | 45 | cpu_stats_file = fopen(CPU_USAGE_STATS_FILENAME, "r"); 46 | 47 | if (!cpu_stats_file) 48 | { 49 | char cpu_stats_file_name[MAXPGPATH]; 50 | snprintf(cpu_stats_file_name, MAXPGPATH, "%s", CPU_USAGE_STATS_FILENAME); 51 | 52 | ereport(WARNING, 53 | (errcode_for_file_access(), 54 | errmsg("can not open file %s for reading cpu usage statistics", 55 | cpu_stats_file_name))); 56 | 57 | cpu_stat->usermode_normal_process = 0; 58 | cpu_stat->usermode_niced_process = 0; 59 | cpu_stat->kernelmode_process = 0; 60 | cpu_stat->idle_mode = 0; 61 | cpu_stat->io_completion = 0; 62 | cpu_stat->servicing_irq = 0; 63 | cpu_stat->servicing_softirq = 0; 64 | return; 65 | } 66 | 67 | /* Get the first line of the file. */ 68 | line_size = getline(&line_buf, &line_buf_size, cpu_stats_file); 69 | 70 | /* Loop through until we are done with the file. */ 71 | while (line_size >= 0) 72 | { 73 | if (strstr(line_buf, "cpu") != NULL) 74 | { 75 | sscanf(line_buf, scan_fmt, &usermode_normal_process, 76 | &usermode_niced_process, 77 | &kernelmode_process, 78 | &idle_mode, 79 | &io_completion, 80 | &servicing_irq, 81 | &servicing_softirq); 82 | 83 | cpu_stat->usermode_normal_process = usermode_normal_process; 84 | cpu_stat->usermode_niced_process = usermode_niced_process; 85 | cpu_stat->kernelmode_process = kernelmode_process; 86 | cpu_stat->idle_mode = idle_mode; 87 | cpu_stat->io_completion = io_completion; 88 | cpu_stat->servicing_irq = servicing_irq; 89 | cpu_stat->servicing_softirq = servicing_softirq; 90 | break; 91 | } 92 | 93 | /* Free the allocated line buffer */ 94 | if (line_buf != NULL) 95 | { 96 | free(line_buf); 97 | line_buf = NULL; 98 | } 99 | 100 | /* Get the next line */ 101 | line_size = getline(&line_buf, &line_buf_size, cpu_stats_file); 102 | } 103 | 104 | /* Free the allocated line buffer */ 105 | if (line_buf != NULL) 106 | { 107 | free(line_buf); 108 | line_buf = NULL; 109 | } 110 | 111 | fclose(cpu_stats_file); 112 | } 113 | 114 | void ReadCPUUsageStatistics(Tuplestorestate *tupstore, TupleDesc tupdesc) 115 | { 116 | Datum values[Natts_cpu_usage_stats]; 117 | bool nulls[Natts_cpu_usage_stats]; 118 | struct cpu_stat first_sample, second_sample; 119 | long long int delta_usermode_normal_process = 0; 120 | long long int delta_usermode_niced_process = 0; 121 | long long int delta_kernelmode_process = 0; 122 | long long int delta_idle_mode = 0; 123 | long long int delta_io_completion = 0; 124 | long long int delta_servicing_irq = 0; 125 | long long int delta_servicing_softirq = 0; 126 | long long int total_delta = 0; 127 | float scale = 100.0; 128 | float f_usermode_normal_process = 0.00; 129 | float f_usermode_niced_process = 0.00; 130 | float f_kernelmode_process = 0.00; 131 | float f_idle_mode = 0.00; 132 | float f_io_completion = 0.00; 133 | float f_servicing_irq = 0.00; 134 | float f_servicing_softirq = 0.00; 135 | 136 | memset(nulls, 0, sizeof(nulls)); 137 | 138 | /* Take the first sample regarding cpu usage statistics */ 139 | cpu_stat_information(&first_sample); 140 | /* sleep for the 100ms between 2 samples tp find cpu usage statistics */ 141 | usleep(150000); 142 | /* Take the second sample regarding cpu usage statistics */ 143 | cpu_stat_information(&second_sample); 144 | 145 | delta_usermode_normal_process = (second_sample.usermode_normal_process - first_sample.usermode_normal_process); 146 | delta_usermode_niced_process = (second_sample.usermode_niced_process - first_sample.usermode_niced_process); 147 | delta_kernelmode_process = (second_sample.kernelmode_process - first_sample.kernelmode_process); 148 | delta_idle_mode = (second_sample.idle_mode - first_sample.idle_mode); 149 | delta_io_completion = (second_sample.io_completion - first_sample.io_completion); 150 | delta_servicing_irq = (second_sample.servicing_irq - first_sample.servicing_irq); 151 | delta_servicing_softirq = (second_sample.servicing_softirq - first_sample.servicing_softirq); 152 | 153 | total_delta = delta_usermode_normal_process + delta_usermode_niced_process + delta_kernelmode_process + 154 | delta_idle_mode + delta_io_completion + delta_servicing_irq + delta_servicing_softirq; 155 | 156 | if (total_delta != 0) 157 | scale = (float)100/(float)total_delta; 158 | 159 | f_usermode_normal_process = (float)(delta_usermode_normal_process * scale); 160 | f_usermode_niced_process = (float)(delta_usermode_niced_process * scale); 161 | f_kernelmode_process = (float)(delta_kernelmode_process * scale); 162 | f_idle_mode = (float)(delta_idle_mode * scale); 163 | f_io_completion = (float)(delta_io_completion * scale); 164 | f_servicing_irq = (float)(delta_servicing_irq * scale); 165 | f_servicing_softirq = (float)(delta_servicing_softirq * scale); 166 | 167 | f_usermode_normal_process = fl_round(f_usermode_normal_process); 168 | f_usermode_niced_process = fl_round(f_usermode_niced_process); 169 | f_kernelmode_process = fl_round(f_kernelmode_process); 170 | f_idle_mode = fl_round(f_idle_mode); 171 | f_io_completion = fl_round(f_io_completion); 172 | f_servicing_irq = fl_round(f_servicing_irq); 173 | f_servicing_softirq = fl_round(f_servicing_softirq); 174 | 175 | values[Anum_usermode_normal_process] = Float4GetDatum(f_usermode_normal_process); 176 | values[Anum_usermode_niced_process] = Float4GetDatum(f_usermode_niced_process); 177 | values[Anum_kernelmode_process] = Float4GetDatum(f_kernelmode_process); 178 | values[Anum_idle_mode] = Float4GetDatum(f_idle_mode); 179 | values[Anum_io_completion] = Float4GetDatum(f_io_completion); 180 | values[Anum_servicing_irq] = Float4GetDatum(f_servicing_irq); 181 | values[Anum_servicing_softirq] = Float4GetDatum(f_servicing_softirq); 182 | 183 | nulls[Anum_percent_user_time] = true; 184 | nulls[Anum_percent_processor_time] = true; 185 | nulls[Anum_percent_privileged_time] = true; 186 | nulls[Anum_percent_interrupt_time] = true; 187 | 188 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 189 | } 190 | -------------------------------------------------------------------------------- /linux/disk_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * disk_info.c 3 | * System disk information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "system_stats.h" 17 | 18 | void ReadDiskInformation(Tuplestorestate *tupstore, TupleDesc tupdesc); 19 | 20 | /* This function is used to ignore the file system types */ 21 | bool ignoreFileSystemTypes(char *fs_mnt) 22 | { 23 | regex_t regex; 24 | int reg_return; 25 | bool ret_value = false; 26 | 27 | reg_return = regcomp(®ex, IGNORE_FILE_SYSTEM_TYPE_REGEX, REG_EXTENDED); 28 | if (reg_return) 29 | { 30 | ereport(DEBUG1, 31 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 32 | errmsg("Could not compile regex"))); 33 | return ret_value; 34 | } 35 | 36 | /* Execute regular expression */ 37 | reg_return = regexec(®ex, fs_mnt, 0, NULL, 0); 38 | if (!reg_return) 39 | ret_value = true; 40 | else if (reg_return == REG_NOMATCH) 41 | ret_value = false; 42 | else 43 | { 44 | ret_value = false; 45 | ereport(DEBUG1, 46 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 47 | errmsg("regex match failed"))); 48 | } 49 | 50 | /* Free memory allocated to the pattern buffer by regcomp() */ 51 | regfree(®ex); 52 | 53 | return ret_value; 54 | } 55 | 56 | /* This function is used to ignore the mount points */ 57 | bool ignoreMountPoints(char *fs_mnt) 58 | { 59 | regex_t regex; 60 | int reg_return; 61 | bool ret_value = false; 62 | 63 | reg_return = regcomp(®ex, IGNORE_MOUNT_POINTS_REGEX, REG_EXTENDED); 64 | if (reg_return) 65 | { 66 | ereport(DEBUG1, 67 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 68 | errmsg("Could not compile regex"))); 69 | return ret_value; 70 | } 71 | 72 | /* Execute regular expression */ 73 | reg_return = regexec(®ex, fs_mnt, 0, NULL, 0); 74 | if (!reg_return) 75 | ret_value = true; 76 | else if (reg_return == REG_NOMATCH) 77 | ret_value = false; 78 | else 79 | { 80 | ret_value = false; 81 | ereport(DEBUG1, 82 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 83 | errmsg("regex match failed"))); 84 | } 85 | 86 | /* Free memory allocated to the pattern buffer by regcomp() */ 87 | regfree(®ex); 88 | 89 | return ret_value; 90 | } 91 | 92 | void ReadDiskInformation(Tuplestorestate *tupstore, TupleDesc tupdesc) 93 | { 94 | Datum values[Natts_disk_info]; 95 | bool nulls[Natts_disk_info]; 96 | char file_system[MAXPGPATH]; 97 | char mount_point[MAXPGPATH]; 98 | char file_system_type[MAXPGPATH]; 99 | FILE *fp = NULL; 100 | uint64 used_space_bytes = 0; 101 | uint64 total_space_bytes = 0; 102 | uint64 available_space_bytes = 0; 103 | uint64 total_inodes = 0; 104 | uint64 used_inodes = 0; 105 | uint64 free_inodes = 0; 106 | 107 | memset(nulls, 0, sizeof(nulls)); 108 | memset(file_system, 0, MAXPGPATH); 109 | memset(mount_point, 0, MAXPGPATH); 110 | memset(file_system_type, 0, MAXPGPATH); 111 | 112 | /* get the file system descriptor */ 113 | fp = setmntent(FILE_SYSTEM_MOUNT_FILE_NAME, "r"); 114 | 115 | if (!fp) 116 | { 117 | char file_name[MAXPGPATH]; 118 | snprintf(file_name, MAXPGPATH, "%s", FILE_SYSTEM_MOUNT_FILE_NAME); 119 | 120 | ereport(DEBUG1, 121 | (errcode_for_file_access(), 122 | errmsg("can not open file %s for reading file system information", 123 | file_name))); 124 | return; 125 | } 126 | else 127 | { 128 | struct mntent *ent; 129 | struct statvfs buf; 130 | 131 | while ((ent = getmntent(fp)) != NULL) 132 | { 133 | if (ignoreFileSystemTypes(ent->mnt_fsname) || ignoreMountPoints(ent->mnt_dir)) 134 | continue; 135 | 136 | memset(&buf, 0, sizeof(buf)); 137 | /* 138 | * If statvfs() fails, just report zeroes. It's better to still 139 | * report statistics for filesystems that we are able to stat, 140 | * rather than failing the whole data. 141 | */ 142 | if (statvfs(ent->mnt_dir, &buf) != 0) 143 | { 144 | ereport(WARNING, 145 | (errcode_for_file_access(), 146 | errmsg("statvfs failed: %s", ent->mnt_dir))); 147 | } 148 | 149 | total_space_bytes = (uint64_t)(buf.f_blocks * buf.f_bsize); 150 | 151 | /* If total space of file system is zero, ignore that from list */ 152 | if (total_space_bytes == 0) 153 | continue; 154 | 155 | used_space_bytes = (uint64_t)((buf.f_blocks - buf.f_bfree) * buf.f_bsize); 156 | available_space_bytes = (uint64_t)(buf.f_bavail * buf.f_bsize); 157 | total_inodes = (uint64_t)buf.f_files; 158 | free_inodes = (uint64_t)buf.f_ffree; 159 | used_inodes = (uint64_t)(total_inodes - free_inodes); 160 | memcpy(file_system, ent->mnt_fsname, strlen(ent->mnt_fsname)); 161 | memcpy(mount_point, ent->mnt_dir, strlen(ent->mnt_dir)); 162 | memcpy(file_system_type, ent->mnt_type, strlen(ent->mnt_type)); 163 | 164 | values[Anum_disk_file_system] = CStringGetTextDatum(file_system); 165 | values[Anum_disk_file_system_type] = CStringGetTextDatum(file_system_type); 166 | values[Anum_disk_mount_point] = CStringGetTextDatum(mount_point); 167 | values[Anum_disk_total_space] = UInt64GetDatum(total_space_bytes); 168 | values[Anum_disk_used_space] = UInt64GetDatum(used_space_bytes); 169 | values[Anum_disk_free_space] = UInt64GetDatum(available_space_bytes); 170 | values[Anum_disk_total_inodes] = UInt64GetDatum(total_inodes); 171 | values[Anum_disk_used_inodes] = UInt64GetDatum(used_inodes); 172 | values[Anum_disk_free_inodes] = UInt64GetDatum(free_inodes); 173 | 174 | nulls[Anum_disk_drive_letter] = true; 175 | nulls[Anum_disk_drive_type] = true; 176 | 177 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 178 | 179 | //reset the value again 180 | memset(file_system, 0, MAXPGPATH); 181 | memset(mount_point, 0, MAXPGPATH); 182 | memset(file_system_type, 0, MAXPGPATH); 183 | used_space_bytes = 0; 184 | total_space_bytes = 0; 185 | available_space_bytes = 0; 186 | total_inodes = 0; 187 | used_inodes = 0; 188 | free_inodes = 0; 189 | } 190 | endmntent(fp); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /linux/io_analysis.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * io_analysis.c 3 | * System IO analysis information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | void ReadIOAnalysisInformation(Tuplestorestate *tupstore, TupleDesc tupdesc); 14 | 15 | /* Function used to get IO statistics of block devices */ 16 | void ReadIOAnalysisInformation(Tuplestorestate *tupstore, TupleDesc tupdesc) 17 | { 18 | FILE *diskstats_file; 19 | Datum values[Natts_io_analysis_info]; 20 | bool nulls[Natts_io_analysis_info]; 21 | char *line_buf = NULL; 22 | size_t line_buf_size = 0; 23 | ssize_t line_size; 24 | char device_name[MAXPGPATH]; 25 | char file_name[MAXPGPATH]; 26 | uint64 read_completed = 0; 27 | uint64 sector_read = 0; 28 | uint64 time_spent_reading_ms = 0; 29 | uint64 write_completed = 0; 30 | uint64 sector_written = 0; 31 | uint64 time_spent_writing_ms = 0; 32 | uint64 sector_size = 512; 33 | const char *scan_fmt = "%*d %*d %s %lld %*lld %lld %lld %lld %*lld %lld %lld"; 34 | 35 | memset(nulls, 0, sizeof(nulls)); 36 | memset(device_name, 0, MAXPGPATH); 37 | memset(file_name, 0, MAXPGPATH); 38 | 39 | /* file name used to read the sector size in bytes */ 40 | snprintf(file_name, MAXPGPATH, "/sys/block/sda/queue/hw_sector_size"); 41 | ReadFileContent(file_name, §or_size); 42 | 43 | diskstats_file = fopen(DISK_IO_STATS_FILE_NAME, "r"); 44 | 45 | if (!diskstats_file) 46 | { 47 | char disk_file_name[MAXPGPATH]; 48 | snprintf(disk_file_name, MAXPGPATH, "%s", DISK_IO_STATS_FILE_NAME); 49 | 50 | ereport(DEBUG1, 51 | (errcode_for_file_access(), 52 | errmsg("can not open file %s for reading disk stats information", 53 | disk_file_name))); 54 | return; 55 | } 56 | 57 | /* Get the first line of the file. */ 58 | line_size = getline(&line_buf, &line_buf_size, diskstats_file); 59 | 60 | /* Loop through until we are done with the file. */ 61 | while (line_size >= 0) 62 | { 63 | sscanf(line_buf, scan_fmt, device_name, &read_completed, §or_read, &time_spent_reading_ms, 64 | &write_completed, §or_written, &time_spent_writing_ms); 65 | 66 | values[Anum_device_name] = CStringGetTextDatum(device_name); 67 | values[Anum_total_read] = UInt64GetDatum(read_completed); 68 | values[Anum_total_write] = UInt64GetDatum(write_completed); 69 | values[Anum_read_bytes] = UInt64GetDatum((uint64)(sector_read * sector_size)); 70 | values[Anum_write_bytes] = UInt64GetDatum((uint64)(sector_written * sector_size)); 71 | values[Anum_read_time_ms] = UInt64GetDatum((uint64)time_spent_reading_ms); 72 | values[Anum_write_time_ms] = UInt64GetDatum((uint64)time_spent_writing_ms); 73 | 74 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 75 | 76 | /* Free the allocated line buffer */ 77 | if (line_buf != NULL) 78 | { 79 | free(line_buf); 80 | line_buf = NULL; 81 | } 82 | 83 | /* Get the next line */ 84 | line_size = getline(&line_buf, &line_buf_size, diskstats_file); 85 | } 86 | 87 | if (line_buf != NULL) 88 | { 89 | free(line_buf); 90 | line_buf = NULL; 91 | } 92 | 93 | fclose(diskstats_file); 94 | } 95 | -------------------------------------------------------------------------------- /linux/load_avg.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * load_avg.c 3 | * System load average information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | void ReadLoadAvgInformations(Tuplestorestate *tupstore, TupleDesc tupdesc); 14 | 15 | void ReadLoadAvgInformations(Tuplestorestate *tupstore, TupleDesc tupdesc) 16 | { 17 | FILE *loadavg_file; 18 | char *line_buf = NULL; 19 | size_t line_buf_size = 0; 20 | ssize_t line_size; 21 | Datum values[Natts_load_avg_info]; 22 | bool nulls[Natts_load_avg_info]; 23 | float4 load_avg_one_minute = 0; 24 | float4 load_avg_five_minutes = 0; 25 | float4 load_avg_ten_minutes = 0; 26 | const char *scan_fmt = "%f %f %f"; 27 | 28 | memset(nulls, 0, sizeof(nulls)); 29 | 30 | loadavg_file = fopen(CPU_IO_LOAD_AVG_FILE, "r"); 31 | 32 | if (!loadavg_file) 33 | { 34 | char loadavg_file_name[MAXPGPATH]; 35 | snprintf(loadavg_file_name, MAXPGPATH, "%s", CPU_IO_LOAD_AVG_FILE); 36 | 37 | ereport(DEBUG1, 38 | (errcode_for_file_access(), 39 | errmsg("can not open file %s for reading load avg information", 40 | loadavg_file_name))); 41 | return; 42 | } 43 | 44 | /* Get the first line of the file. */ 45 | line_size = getline(&line_buf, &line_buf_size, loadavg_file); 46 | 47 | /* Loop through until we are done with the file. */ 48 | if (line_size >= 0) 49 | { 50 | sscanf(line_buf, scan_fmt, &load_avg_one_minute, &load_avg_five_minutes, &load_avg_ten_minutes); 51 | 52 | values[Anum_load_avg_one_minute] = Float4GetDatum(load_avg_one_minute); 53 | values[Anum_load_avg_five_minutes] = Float4GetDatum(load_avg_five_minutes); 54 | values[Anum_load_avg_ten_minutes] = Float4GetDatum(load_avg_ten_minutes); 55 | 56 | nulls[Anum_load_avg_fifteen_minutes] = true; 57 | 58 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 59 | 60 | //reset the value again 61 | load_avg_one_minute = 0; 62 | load_avg_five_minutes = 0; 63 | load_avg_ten_minutes = 0; 64 | } 65 | 66 | if (line_buf != NULL) 67 | { 68 | free(line_buf); 69 | line_buf = NULL; 70 | } 71 | 72 | fclose(loadavg_file); 73 | } 74 | -------------------------------------------------------------------------------- /linux/memory_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * memory_info.c 3 | * System memory information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | #include "postgres.h" 10 | #include "system_stats.h" 11 | 12 | void ReadMemoryInformation(Tuplestorestate *tupstore, TupleDesc tupdesc); 13 | 14 | void ReadMemoryInformation(Tuplestorestate *tupstore, TupleDesc tupdesc) 15 | { 16 | FILE *memory_file; 17 | Datum values[Natts_memory_info]; 18 | bool nulls[Natts_memory_info]; 19 | char *line_buf = NULL; 20 | size_t line_buf_size = 0; 21 | int line_count = 0; 22 | ssize_t line_size; 23 | uint64 total_memory_bytes = 0; 24 | uint64 free_memory_bytes = 0; 25 | uint64 used_memory_bytes = 0; 26 | uint64 cached_bytes = 0; 27 | uint64 swap_total_bytes = 0; 28 | uint64 swap_free_bytes = 0; 29 | uint64 swap_used_bytes = 0; 30 | 31 | memset(nulls, 0, sizeof(nulls)); 32 | 33 | /* Open the file required to read all the memory information */ 34 | memory_file = fopen(MEMORY_FILE_NAME, "r"); 35 | 36 | if (!memory_file) 37 | { 38 | char memory_file_name[MAXPGPATH]; 39 | snprintf(memory_file_name, MAXPGPATH, "%s", MEMORY_FILE_NAME); 40 | 41 | ereport(DEBUG1, 42 | (errcode_for_file_access(), 43 | errmsg("can not open file %s for reading memory information", 44 | memory_file_name))); 45 | return; 46 | } 47 | 48 | /* Get the first line of the file. */ 49 | line_size = getline(&line_buf, &line_buf_size, memory_file); 50 | 51 | /* Loop through until we are done with the file. */ 52 | while (line_size >= 0) 53 | { 54 | /* Read the total memory of the system */ 55 | char *mem_total = strstr(line_buf, "MemTotal:"); 56 | char *mem_free = NULL; 57 | char *cached_mem = NULL; 58 | char *c_swap_total = NULL; 59 | char *c_swap_free = NULL; 60 | if (mem_total != NULL && mem_total == line_buf) 61 | { 62 | line_count++; 63 | total_memory_bytes = ConvertToBytes(line_buf); 64 | } 65 | 66 | /* Read the free memory of the system */ 67 | mem_free = strstr(line_buf, "MemFree:"); 68 | if (mem_free != NULL && mem_free == line_buf) 69 | { 70 | line_count++; 71 | free_memory_bytes = ConvertToBytes(line_buf); 72 | } 73 | 74 | /* Read the cached memory of the system */ 75 | cached_mem = strstr(line_buf, "Cached:"); 76 | if (cached_mem != NULL && cached_mem == line_buf) 77 | { 78 | line_count++; 79 | cached_bytes = ConvertToBytes(line_buf); 80 | } 81 | 82 | /* Read the total swap memory of the system */ 83 | c_swap_total = strstr(line_buf, "SwapTotal:"); 84 | if (c_swap_total != NULL && c_swap_total == line_buf) 85 | { 86 | line_count++; 87 | swap_total_bytes = ConvertToBytes(line_buf); 88 | } 89 | 90 | /* Read the free swap memory of the system */ 91 | c_swap_free = strstr(line_buf, "SwapFree:"); 92 | if (c_swap_free != NULL && c_swap_free == line_buf) 93 | { 94 | line_count++; 95 | swap_free_bytes = ConvertToBytes(line_buf); 96 | } 97 | 98 | used_memory_bytes = total_memory_bytes - free_memory_bytes; 99 | swap_used_bytes = swap_total_bytes - swap_free_bytes; 100 | 101 | // Check if we get all lines, add as row 102 | if (line_count == MEMORY_READ_COUNT) 103 | { 104 | values[Anum_total_memory] = UInt64GetDatum(total_memory_bytes); 105 | values[Anum_free_memory] = UInt64GetDatum(free_memory_bytes); 106 | values[Anum_used_memory] = UInt64GetDatum(used_memory_bytes); 107 | values[Anum_total_cache_memory] = UInt64GetDatum(cached_bytes); 108 | values[Anum_swap_total_memory] = UInt64GetDatum(swap_total_bytes); 109 | values[Anum_swap_free_memory] = UInt64GetDatum(swap_free_bytes); 110 | values[Anum_swap_used_memory] = UInt64GetDatum(swap_used_bytes); 111 | 112 | /* set the NULL value as it is not for this platform */ 113 | nulls[Anum_kernel_total_memory] = true; 114 | nulls[Anum_kernel_paged_memory] = true; 115 | nulls[Anum_kernel_nonpaged_memory] = true; 116 | nulls[Anum_total_page_file] = true; 117 | nulls[Anum_avail_page_file] = true; 118 | 119 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 120 | 121 | /* Free the allocated line buffer */ 122 | if (line_buf != NULL) 123 | { 124 | free(line_buf); 125 | line_buf = NULL; 126 | } 127 | 128 | break; 129 | } 130 | 131 | /* Free the allocated line buffer */ 132 | if (line_buf != NULL) 133 | { 134 | free(line_buf); 135 | line_buf = NULL; 136 | } 137 | 138 | /* Get the next line */ 139 | line_size = getline(&line_buf, &line_buf_size, memory_file); 140 | } 141 | 142 | /* Free the allocated line buffer */ 143 | if (line_buf != NULL) 144 | { 145 | free(line_buf); 146 | line_buf = NULL; 147 | } 148 | 149 | /* Close the file now that we are done with it */ 150 | fclose(memory_file); 151 | } 152 | -------------------------------------------------------------------------------- /linux/network_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * network_info.c 3 | * System network information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | void ReadFileContent(const char *file_name, uint64 *data); 19 | void ReadReceiveBytes(const char *interface, uint64 *rx_bytes); 20 | void ReadTransmitBytes(const char *interface, uint64 *tx_bytes); 21 | void ReadReceivePackets(const char *interface, uint64 *rx_packets); 22 | void ReadTransmitPackets(const char *interface, uint64 *tx_packets); 23 | void ReadReceiveErrors(const char *interface, uint64 *rx_errors); 24 | void ReadTransmitErrors(const char *interface, uint64 *tx_errors); 25 | void ReadReceiveDropped(const char *interface, uint64 *rx_dropped); 26 | void ReadTransmitDropped(const char *interface, uint64 *tx_dropped); 27 | void ReadSpeedMbps(const char *interface, uint64 *speed); 28 | void ReadNetworkInformations(Tuplestorestate *tupstore, TupleDesc tupdesc); 29 | 30 | /* This function is used to read the number of bytes received for specified network interface */ 31 | void ReadReceiveBytes(const char *interface, uint64 *rx_bytes) 32 | { 33 | char file_name[MAXPGPATH]; 34 | memset(file_name, 0, MAXPGPATH); 35 | 36 | /* file name used to read the number of bytes received */ 37 | snprintf(file_name, MAXPGPATH, "/sys/class/net/%s/statistics/rx_bytes", interface); 38 | ReadFileContent(file_name, rx_bytes); 39 | } 40 | 41 | /* This function is used to read the number of bytes transmitted for specified network interface */ 42 | void ReadTransmitBytes(const char *interface, uint64 *tx_bytes) 43 | { 44 | char file_name[MAXPGPATH]; 45 | memset(file_name, 0, MAXPGPATH); 46 | 47 | /* file name used to read the number of bytes transmitted */ 48 | snprintf(file_name, MAXPGPATH, "/sys/class/net/%s/statistics/tx_bytes", interface); 49 | ReadFileContent(file_name, tx_bytes); 50 | } 51 | 52 | /* This function is used to read the number of packets received for specified network interface */ 53 | void ReadReceivePackets(const char *interface, uint64 *rx_packets) 54 | { 55 | char file_name[MAXPGPATH]; 56 | memset(file_name, 0, MAXPGPATH); 57 | 58 | /* file name used to read the number of packets received */ 59 | snprintf(file_name, MAXPGPATH, "/sys/class/net/%s/statistics/rx_packets", interface); 60 | ReadFileContent(file_name, rx_packets); 61 | } 62 | 63 | /* This function is used to read the number of packets transmitted for specified network interface */ 64 | void ReadTransmitPackets(const char *interface, uint64 *tx_packets) 65 | { 66 | char file_name[MAXPGPATH]; 67 | memset(file_name, 0, MAXPGPATH); 68 | 69 | /* file name used to read the number of packets transmitted */ 70 | snprintf(file_name, MAXPGPATH, "/sys/class/net/%s/statistics/tx_packets", interface); 71 | ReadFileContent(file_name, tx_packets); 72 | } 73 | 74 | /* This function is used to read the number of errors during receiver for specified network interface */ 75 | void ReadReceiveErrors(const char *interface, uint64 *rx_errors) 76 | { 77 | char file_name[MAXPGPATH]; 78 | memset(file_name, 0, MAXPGPATH); 79 | 80 | /* file name used to read the number of errors during receiver */ 81 | snprintf(file_name, MAXPGPATH, "/sys/class/net/%s/statistics/rx_errors", interface); 82 | ReadFileContent(file_name, rx_errors); 83 | } 84 | 85 | /* This function is used to read the number of errors during transmission for specified network interface */ 86 | void ReadTransmitErrors(const char *interface, uint64 *tx_errors) 87 | { 88 | char file_name[MAXPGPATH]; 89 | memset(file_name, 0, MAXPGPATH); 90 | 91 | /* file name used to read the number of errors during transmission */ 92 | snprintf(file_name, MAXPGPATH, "/sys/class/net/%s/statistics/tx_errors", interface); 93 | ReadFileContent(file_name, tx_errors); 94 | } 95 | 96 | /* This function is used to read the number of packets dropped during receiver for specified network interface */ 97 | void ReadReceiveDropped(const char *interface, uint64 *rx_dropped) 98 | { 99 | char file_name[MAXPGPATH]; 100 | memset(file_name, 0, MAXPGPATH); 101 | 102 | /* file name used to read the number of packets dropped during receiver */ 103 | snprintf(file_name, MAXPGPATH, "/sys/class/net/%s/statistics/rx_dropped", interface); 104 | ReadFileContent(file_name, rx_dropped); 105 | } 106 | 107 | /* This function is used to read the number of packets dropped during transmission for specified network interface */ 108 | void ReadTransmitDropped(const char *interface, uint64 *tx_dropped) 109 | { 110 | char file_name[MAXPGPATH]; 111 | memset(file_name, 0, MAXPGPATH); 112 | 113 | /* file name used to read the number of packets dropped during transmission */ 114 | snprintf(file_name, MAXPGPATH, "/sys/class/net/%s/statistics/tx_dropped", interface); 115 | ReadFileContent(file_name, tx_dropped); 116 | } 117 | 118 | /* This function is used to read the speed in Mbps for specified network interface */ 119 | void ReadSpeedMbps(const char *interface, uint64 *speed) 120 | { 121 | char file_name[MAXPGPATH]; 122 | memset(file_name, 0, MAXPGPATH); 123 | 124 | /* file name used to read the speed of interface in Mbps */ 125 | snprintf(file_name, MAXPGPATH, "/sys/class/net/%s/speed", interface); 126 | ReadFileContent(file_name, speed); 127 | } 128 | 129 | void ReadNetworkInformations(Tuplestorestate *tupstore, TupleDesc tupdesc) 130 | { 131 | Datum values[Natts_network_info]; 132 | bool nulls[Natts_network_info]; 133 | char interface_name[MAXPGPATH]; 134 | char ipv4_address[MAXPGPATH]; 135 | uint64 speed_mbps = 0; 136 | uint64 tx_bytes = 0; 137 | uint64 tx_packets = 0; 138 | uint64 tx_errors = 0; 139 | uint64 tx_dropped = 0; 140 | uint64 rx_bytes = 0; 141 | uint64 rx_packets = 0; 142 | uint64 rx_errors = 0; 143 | uint64 rx_dropped = 0; 144 | 145 | // First find out interface and ip address of that interface 146 | struct ifaddrs *ifaddr; 147 | struct ifaddrs *ifa; 148 | int ret_val; 149 | char host[MAXPGPATH]; 150 | 151 | memset(nulls, 0, sizeof(nulls)); 152 | memset(interface_name, 0, MAXPGPATH); 153 | memset(ipv4_address, 0, MAXPGPATH); 154 | memset(host, 0, MAXPGPATH); 155 | 156 | /* Below function is used to creates a linked list of structures describing 157 | * the network interfaces of the local system 158 | */ 159 | if (getifaddrs(&ifaddr) == -1) 160 | { 161 | ereport(DEBUG1, 162 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 163 | errmsg("Failed to get network interface"))); 164 | return; 165 | } 166 | 167 | /* Iterate through all network interfaces */ 168 | for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) 169 | { 170 | /* Do not get network interface name so continue reading other interfaces */ 171 | if (ifa->ifa_addr == NULL) 172 | continue; 173 | 174 | /* Below function is used to get address to name translation */ 175 | ret_val = getnameinfo(ifa->ifa_addr,sizeof(struct sockaddr_in),host, MAXPGPATH, NULL, 0, NI_NUMERICHOST); 176 | 177 | if(ifa->ifa_addr->sa_family == AF_INET) 178 | { 179 | if (ret_val != 0) 180 | { 181 | ereport(ERROR, 182 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 183 | errmsg("getnameinfo() failed: %s", gai_strerror(ret_val)))); 184 | nulls[Anum_net_ipv4_address] = true; 185 | } 186 | 187 | memcpy(interface_name, ifa->ifa_name, strlen(ifa->ifa_name)); 188 | memcpy(ipv4_address, host, MAXPGPATH); 189 | 190 | ReadSpeedMbps(interface_name, &speed_mbps); 191 | ReadReceiveBytes(interface_name, &rx_bytes); 192 | ReadTransmitBytes(interface_name, &tx_bytes); 193 | ReadReceivePackets(interface_name, &rx_packets); 194 | ReadTransmitPackets(interface_name, &tx_packets); 195 | ReadReceiveErrors(interface_name, &rx_errors); 196 | ReadTransmitErrors(interface_name, &tx_errors); 197 | ReadReceiveDropped(interface_name, &rx_dropped); 198 | ReadTransmitDropped(interface_name, &tx_dropped); 199 | 200 | values[Anum_net_interface_name] = CStringGetTextDatum(interface_name); 201 | values[Anum_net_ipv4_address] = CStringGetTextDatum(ipv4_address); 202 | values[Anum_net_speed_mbps] = UInt64GetDatum(speed_mbps); 203 | values[Anum_net_tx_bytes] = UInt64GetDatum(tx_bytes); 204 | values[Anum_net_tx_packets] = UInt64GetDatum(tx_packets); 205 | values[Anum_net_tx_errors] = UInt64GetDatum(tx_errors); 206 | values[Anum_net_tx_dropped] = UInt64GetDatum(tx_dropped); 207 | values[Anum_net_rx_bytes] = UInt64GetDatum(rx_bytes); 208 | values[Anum_net_rx_packets] = UInt64GetDatum(rx_packets); 209 | values[Anum_net_rx_errors] = UInt64GetDatum(rx_errors); 210 | values[Anum_net_rx_dropped] = UInt64GetDatum(rx_dropped); 211 | 212 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 213 | 214 | //reset the value again 215 | memset(interface_name, 0, MAXPGPATH); 216 | memset(ipv4_address, 0, MAXPGPATH); 217 | speed_mbps = 0; 218 | tx_bytes = 0; 219 | tx_packets = 0; 220 | tx_errors = 0; 221 | tx_dropped = 0; 222 | rx_bytes = 0; 223 | rx_packets = 0; 224 | rx_errors = 0; 225 | rx_dropped = 0; 226 | } 227 | } 228 | 229 | freeifaddrs(ifaddr); 230 | } 231 | -------------------------------------------------------------------------------- /linux/os_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * os_info.c 3 | * Operating system information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | bool total_opened_handle(int *total_handles); 18 | void ReadOSInformations(Tuplestorestate *tupstore, TupleDesc tupdesc); 19 | 20 | bool total_opened_handle(int *total_handles) 21 | { 22 | FILE *fp; 23 | char *line_buf = NULL; 24 | size_t line_buf_size = 0; 25 | ssize_t line_size; 26 | int allocated_handle_count; 27 | int unallocated_handle_count; 28 | int max_handle_count; 29 | const char *scan_fmt = "%d %d %d"; 30 | 31 | fp = fopen(OS_HANDLE_READ_FILE_PATH, "r"); 32 | 33 | if (!fp) 34 | { 35 | ereport(DEBUG1, (errmsg("can not open file for reading handle informations"))); 36 | return false; 37 | } 38 | 39 | /* Get the first line of the file. */ 40 | line_size = getline(&line_buf, &line_buf_size, fp); 41 | 42 | /* Loop through until we are done with the file. */ 43 | if (line_size >= 0) 44 | sscanf(line_buf, scan_fmt, &allocated_handle_count, &unallocated_handle_count, &max_handle_count); 45 | 46 | if (line_buf != NULL) 47 | { 48 | free(line_buf); 49 | line_buf = NULL; 50 | } 51 | 52 | fclose(fp); 53 | 54 | *total_handles = allocated_handle_count; 55 | 56 | return true; 57 | } 58 | 59 | void ReadOSInformations(Tuplestorestate *tupstore, TupleDesc tupdesc) 60 | { 61 | struct utsname uts; 62 | struct sysinfo s_info; 63 | Datum values[Natts_os_info]; 64 | bool nulls[Natts_os_info]; 65 | char host_name[MAXPGPATH]; 66 | char domain_name[MAXPGPATH]; 67 | char version[MAXPGPATH]; 68 | char architecture[MAXPGPATH]; 69 | char os_name[MAXPGPATH]; 70 | int ret_val; 71 | FILE *os_info_file; 72 | char *line_buf = NULL; 73 | size_t line_buf_size = 0; 74 | ssize_t line_size; 75 | int active_processes = 0; 76 | int running_processes = 0; 77 | int sleeping_processes = 0; 78 | int stopped_processes = 0; 79 | int zombie_processes = 0; 80 | int total_threads = 0; 81 | int handle_count = 0; 82 | 83 | memset(nulls, 0, sizeof(nulls)); 84 | memset(host_name, 0, MAXPGPATH); 85 | memset(domain_name, 0, MAXPGPATH); 86 | memset(version, 0, MAXPGPATH); 87 | memset(architecture, 0, MAXPGPATH); 88 | memset(os_name, 0, MAXPGPATH); 89 | 90 | ret_val = uname(&uts); 91 | /* if it returns not zero means it fails so set null values */ 92 | if (ret_val != 0) 93 | { 94 | nulls[Anum_os_version] = true; 95 | nulls[Anum_architecture] = true; 96 | } 97 | else 98 | { 99 | snprintf(version, MAXPGPATH, "%s %s", uts.sysname, uts.release); 100 | memcpy(architecture, uts.machine, strlen(uts.machine)); 101 | } 102 | 103 | /* Function used to get the host name of the system */ 104 | if (gethostname(host_name, sizeof(host_name)) != 0) 105 | ereport(DEBUG1, 106 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 107 | errmsg("error while getting host name"))); 108 | 109 | /* Function used to get the domain name of the system */ 110 | if (getdomainname(domain_name, sizeof(domain_name)) != 0) 111 | ereport(DEBUG1, 112 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 113 | errmsg("error while getting domain name"))); 114 | 115 | /*If hostname or domain name is empty, set the value to NULL */ 116 | if (strlen(host_name) == 0) 117 | nulls[Anum_host_name] = true; 118 | if (strlen(domain_name) == 0) 119 | nulls[Anum_domain_name] = true; 120 | 121 | os_info_file = fopen(OS_INFO_FILE_NAME, "r"); 122 | 123 | if (!os_info_file) 124 | { 125 | char os_info_file_name[MAXPGPATH]; 126 | snprintf(os_info_file_name, MAXPGPATH, "%s", OS_INFO_FILE_NAME); 127 | 128 | ereport(DEBUG1, 129 | (errcode_for_file_access(), 130 | errmsg("can not open file %s for reading os information", 131 | os_info_file_name))); 132 | 133 | nulls[Anum_os_name] = true; 134 | } 135 | else 136 | { 137 | /* Get the first line of the file. */ 138 | line_size = getline(&line_buf, &line_buf_size, os_info_file); 139 | 140 | /* Loop through until we are done with the file. */ 141 | while (line_size >= 0) 142 | { 143 | int len = strlen(line_buf); 144 | if (strstr(line_buf, OS_DESC_SEARCH_TEXT) != NULL) 145 | memcpy(os_name, (line_buf + strlen(OS_DESC_SEARCH_TEXT)), (len - strlen(OS_DESC_SEARCH_TEXT))); 146 | 147 | /* Free the allocated line buffer */ 148 | if (line_buf != NULL) 149 | { 150 | free(line_buf); 151 | line_buf = NULL; 152 | } 153 | 154 | /* Get the next line */ 155 | line_size = getline(&line_buf, &line_buf_size, os_info_file); 156 | } 157 | 158 | /* Free the allocated line buffer */ 159 | if (line_buf != NULL) 160 | { 161 | free(line_buf); 162 | line_buf = NULL; 163 | } 164 | 165 | fclose(os_info_file); 166 | } 167 | 168 | /* Get total file descriptor, thread count and process count */ 169 | if (read_process_status(&active_processes, &running_processes, &sleeping_processes, 170 | &stopped_processes, &zombie_processes, &total_threads)) 171 | { 172 | values[Anum_os_process_count] = active_processes; 173 | values[Anum_os_thread_count] = total_threads; 174 | } 175 | else 176 | { 177 | nulls[Anum_os_process_count] = true; 178 | nulls[Anum_os_thread_count] = true; 179 | } 180 | 181 | /* licenced user is not applicable to linux so return NULL */ 182 | nulls[Anum_os_boot_time] = true; 183 | 184 | /* count the total number of opended file descriptor */ 185 | if (!total_opened_handle(&handle_count)) 186 | nulls[Anum_os_handle_count] = true; 187 | 188 | if (sysinfo(&s_info) != 0) 189 | nulls[Anum_os_up_since_seconds] = true; 190 | else 191 | values[Anum_os_up_since_seconds] = Int32GetDatum((int)s_info.uptime); 192 | 193 | values[Anum_os_name] = CStringGetTextDatum(os_name); 194 | values[Anum_os_version] = CStringGetTextDatum(version); 195 | values[Anum_host_name] = CStringGetTextDatum(host_name); 196 | values[Anum_domain_name] = CStringGetTextDatum(domain_name); 197 | values[Anum_os_handle_count] = Int32GetDatum(handle_count); 198 | values[Anum_os_architecture] = CStringGetTextDatum(architecture); 199 | 200 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 201 | } 202 | -------------------------------------------------------------------------------- /linux/process_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * process_info.c 3 | * System process information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | void ReadProcessInformations(Tuplestorestate *tupstore, TupleDesc tupdesc); 14 | 15 | void ReadProcessInformations(Tuplestorestate *tupstore, TupleDesc tupdesc) 16 | { 17 | int active_processes = 0; 18 | int running_processes = 0; 19 | int sleeping_processes = 0; 20 | int stopped_processes = 0; 21 | int zombie_processes = 0; 22 | int total_threads = 0; 23 | Datum values[Natts_process_info]; 24 | bool nulls[Natts_process_info]; 25 | 26 | memset(nulls, 0, sizeof(nulls)); 27 | 28 | if (read_process_status(&active_processes, &running_processes, &sleeping_processes, 29 | &stopped_processes, &zombie_processes, &total_threads)) 30 | { 31 | values[Anum_no_of_total_processes] = Int32GetDatum(active_processes); 32 | values[Anum_no_of_running_processes] = Int32GetDatum(running_processes); 33 | values[Anum_no_of_sleeping_processes] = Int32GetDatum(sleeping_processes); 34 | values[Anum_no_of_stopped_processes] = Int32GetDatum(stopped_processes); 35 | values[Anum_no_of_zombie_processes] = Int32GetDatum(zombie_processes); 36 | } 37 | else 38 | { 39 | nulls[Anum_no_of_total_processes] = true; 40 | nulls[Anum_no_of_running_processes] = true; 41 | nulls[Anum_no_of_sleeping_processes] = true; 42 | nulls[Anum_no_of_stopped_processes] = true; 43 | nulls[Anum_no_of_zombie_processes] = true; 44 | } 45 | 46 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 47 | } 48 | -------------------------------------------------------------------------------- /linux/system_stats_utils.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * system_stats_utils.c 3 | * Defined required utility functions to fetch 4 | * system statistics information 5 | * 6 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 7 | * 8 | *------------------------------------------------------------------------ 9 | */ 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | char* leftTrimStr(char* s); 21 | char* rightTrimStr(char* s); 22 | 23 | /* Function used to convert KB, MB, GB to bytes */ 24 | uint64_t ConvertToBytes(char *line_buf) 25 | { 26 | uint64_t value = 0; 27 | char *found = strstr(line_buf, ":"); 28 | if (found) 29 | { 30 | char result[MAXPGPATH]; 31 | char suffix[MAXPGPATH]; 32 | char *token = NULL; 33 | int icount = 0; 34 | memset(result, 0x00, MAXPGPATH); 35 | memset(suffix, 0x00, MAXPGPATH); 36 | found = trimStr((found+1)); 37 | 38 | token = strtok(found, " "); 39 | while( token != NULL ) 40 | { 41 | if (icount == 0) 42 | memcpy(result, token, strlen(token)); 43 | else 44 | { 45 | memcpy(suffix, token, strlen(token)); 46 | break; 47 | } 48 | 49 | token = strtok(NULL, " ");icount++; 50 | icount++; 51 | } 52 | 53 | if (strcasecmp(suffix, "kb") == 0) 54 | { 55 | value = (uint64_t)atoll(result); 56 | value = value * 1024; 57 | } 58 | else if (strcasecmp(suffix, "mb") == 0) 59 | { 60 | value = (uint64_t)atoll(result); 61 | value = value * 1024 * 1024; 62 | } 63 | else if (strcasecmp(suffix, "gb") == 0) 64 | { 65 | value = (uint64_t)atoll(result); 66 | value = value * 1024 * 1024 * 1024; 67 | } 68 | else 69 | value = (uint64_t)atoll(result); 70 | } 71 | return value; 72 | } 73 | 74 | /* Function used to check the string is a number or not */ 75 | bool stringIsNumber(char *str) 76 | { 77 | bool ret_val = true; 78 | int len; 79 | size_t index; 80 | 81 | if (str == NULL) 82 | return !ret_val; 83 | 84 | len = strlen(str); 85 | for(index = 0; index < len; index++) 86 | { 87 | if( !isdigit(str[index])) 88 | return !ret_val; 89 | } 90 | return ret_val; 91 | } 92 | 93 | /* Function used to trim the string from left only*/ 94 | char* leftTrimStr(char* s) 95 | { 96 | char* new_str = s; 97 | 98 | while (isspace( *new_str)) 99 | { 100 | ++new_str; 101 | } 102 | 103 | memmove( s, new_str, strlen( new_str) + 1); 104 | 105 | return s; 106 | } 107 | 108 | /* Function used to trim the string from right only */ 109 | char* rightTrimStr(char* s) 110 | { 111 | char* end = s + strlen( s); 112 | 113 | while ((end != s) && isspace( *(end-1))) 114 | { 115 | --end; 116 | } 117 | 118 | *end = '\0'; 119 | 120 | return s; 121 | } 122 | 123 | /* Function used to trim the string from both left and right */ 124 | char* trimStr( char* s) 125 | { 126 | return rightTrimStr(leftTrimStr(s)); 127 | } 128 | 129 | /* Round the value by 2 decimal points */ 130 | float fl_round(float val) 131 | { 132 | float value = (int)(val * 100 + 0.5); 133 | return (float)value / 100; 134 | } 135 | 136 | bool read_process_status(int *active_processes, int *running_processes, 137 | int *sleeping_processes, int *stopped_processes, int *zombie_processes, int *total_threads) 138 | { 139 | FILE *fpstat; 140 | DIR *dirp; 141 | struct dirent *ent; 142 | char file_name[MIN_BUFFER_SIZE]; 143 | char process_type; 144 | unsigned int running_threads; 145 | int active_pro = 0; 146 | int running_pro = 0; 147 | int sleeping_pro = 0; 148 | int stopped_pro = 0; 149 | int zombie_pro = 0; 150 | 151 | dirp = opendir(PROC_FILE_SYSTEM_PATH); 152 | if (!dirp) 153 | { 154 | ereport(DEBUG1, (errmsg("Error opening /proc directory"))); 155 | return false; 156 | } 157 | 158 | /* Read the proc directory for process status */ 159 | while ((ent = readdir(dirp)) != NULL) 160 | { 161 | memset(file_name, 0x00, MIN_BUFFER_SIZE); 162 | process_type = '\0'; 163 | 164 | /* Iterate only digit as name because it is process id */ 165 | if (!isdigit(*ent->d_name)) 166 | continue; 167 | 168 | active_pro++; 169 | 170 | snprintf(file_name, MIN_BUFFER_SIZE, "/proc/%s/stat", ent->d_name); 171 | 172 | fpstat = fopen(file_name, "r"); 173 | if (fpstat == NULL) 174 | continue; 175 | 176 | if (fscanf(fpstat, "%*d %*s %c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %*u %*u" 177 | "%*d %*d %*d %*d %d %*d %*u %*u %*d", &process_type, &running_threads) == EOF) 178 | ereport(DEBUG1, (errmsg("Error in parsing file '%s'", file_name))); 179 | 180 | if (process_type == 'R') 181 | running_pro++; 182 | else if (process_type == 'S' || process_type == 'D') 183 | sleeping_pro++; 184 | else if (process_type == 'T') 185 | stopped_pro++; 186 | else if (process_type == 'Z') 187 | zombie_pro++; 188 | else 189 | ereport(DEBUG1, (errmsg("Invalid process type '%c'", process_type))); 190 | 191 | *total_threads = *total_threads + running_threads; 192 | 193 | fclose(fpstat); 194 | fpstat = NULL; 195 | } 196 | 197 | *active_processes = active_pro; 198 | *running_processes = running_pro; 199 | *sleeping_processes = sleeping_pro; 200 | *stopped_processes = stopped_pro; 201 | *zombie_processes = zombie_pro; 202 | 203 | closedir(dirp); 204 | dirp = NULL; 205 | 206 | return true; 207 | } 208 | 209 | 210 | void ReadFileContent(const char *file_name, uint64 *data) 211 | { 212 | FILE *fp = NULL; 213 | char *line_buf = NULL; 214 | size_t line_buf_size = 0; 215 | ssize_t line_size = 0; 216 | 217 | /* Read the file of given file name */ 218 | fp = fopen(file_name, "r"); 219 | 220 | if (!fp) 221 | { 222 | char net_file_name[MAXPGPATH]; 223 | snprintf(net_file_name, MAXPGPATH, "%s", file_name); 224 | 225 | ereport(DEBUG1, 226 | (errcode_for_file_access(), 227 | errmsg("can not open file %s for reading network statistics", 228 | net_file_name))); 229 | return; 230 | } 231 | 232 | /* Get the first line of the file. */ 233 | line_size = getline(&line_buf, &line_buf_size, fp); 234 | 235 | /* Read the content of the file and convert to int64 from string */ 236 | if (line_size > 0) 237 | *data = atoll(line_buf); 238 | 239 | /* Free the allocated line buffer */ 240 | if (line_buf != NULL) 241 | { 242 | free(line_buf); 243 | line_buf = NULL; 244 | } 245 | 246 | fclose(fp); 247 | } 248 | -------------------------------------------------------------------------------- /system_stats--1.0--2.0.sql: -------------------------------------------------------------------------------- 1 | -- No function has changed 2 | -------------------------------------------------------------------------------- /system_stats--1.0.sql: -------------------------------------------------------------------------------- 1 | /* system statistics extension */ 2 | 3 | -- complain if script is sourced in psql, rather than via CREATE EXTENSION 4 | \echo Use "CREATE EXTENSION system_stats" to load this file. \quit 5 | 6 | -- role to be assigned while executing functions of system stats 7 | -- before creating role, check the role exists or not. It may possible 8 | -- that user want to create extension in multiple database of same server 9 | DO $$ 10 | BEGIN 11 | IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'monitor_system_stats') THEN 12 | CREATE ROLE monitor_system_stats WITH 13 | NOLOGIN 14 | NOSUPERUSER 15 | NOCREATEDB 16 | NOCREATEROLE 17 | INHERIT 18 | NOREPLICATION 19 | CONNECTION LIMIT -1; 20 | END IF; 21 | END 22 | $$; 23 | 24 | -- Operating system information function 25 | CREATE FUNCTION pg_sys_os_info( 26 | OUT name text, 27 | OUT version text, 28 | OUT host_name text, 29 | OUT domain_name text, 30 | OUT handle_count int, 31 | OUT process_count int, 32 | OUT thread_count int, 33 | OUT architecture text, 34 | OUT last_bootup_time text, 35 | OUT os_up_since_seconds int 36 | ) 37 | RETURNS SETOF record 38 | AS 'MODULE_PATHNAME' 39 | LANGUAGE C; 40 | 41 | REVOKE ALL ON FUNCTION pg_sys_os_info() FROM PUBLIC; 42 | GRANT EXECUTE ON FUNCTION pg_sys_os_info() TO monitor_system_stats; 43 | 44 | -- System CPU information function 45 | CREATE FUNCTION pg_sys_cpu_info( 46 | OUT vendor text, 47 | OUT description text, 48 | OUT model_name text, 49 | OUT processor_type int, 50 | OUT logical_processor int, 51 | OUT physical_processor int, 52 | OUT no_of_cores int, 53 | OUT architecture text, 54 | OUT clock_speed_hz int8, 55 | OUT cpu_type text, 56 | OUT cpu_family text, 57 | OUT byte_order text, 58 | OUT l1dcache_size int, 59 | OUT l1icache_size int, 60 | OUT l2cache_size int, 61 | OUT l3cache_size int 62 | ) 63 | RETURNS SETOF record 64 | AS 'MODULE_PATHNAME' 65 | LANGUAGE C; 66 | 67 | REVOKE ALL ON FUNCTION pg_sys_cpu_info() FROM PUBLIC; 68 | GRANT EXECUTE ON FUNCTION pg_sys_cpu_info() TO monitor_system_stats; 69 | 70 | -- Memory information function 71 | CREATE FUNCTION pg_sys_memory_info( 72 | OUT total_memory int8, 73 | OUT used_memory int8, 74 | OUT free_memory int8, 75 | OUT swap_total int8, 76 | OUT swap_used int8, 77 | OUT swap_free int8, 78 | OUT cache_total int8, 79 | OUT kernel_total int8, 80 | OUT kernel_paged int8, 81 | OUT kernel_non_paged int8, 82 | OUT total_page_file int8, 83 | OUT avail_page_file int8 84 | ) 85 | RETURNS SETOF record 86 | AS 'MODULE_PATHNAME' 87 | LANGUAGE C; 88 | 89 | REVOKE ALL ON FUNCTION pg_sys_memory_info() FROM PUBLIC; 90 | GRANT EXECUTE ON FUNCTION pg_sys_memory_info() TO monitor_system_stats; 91 | 92 | -- Load average information function 93 | CREATE FUNCTION pg_sys_load_avg_info( 94 | OUT load_avg_one_minute float4, 95 | OUT load_avg_five_minutes float4, 96 | OUT load_avg_ten_minutes float4, 97 | OUT load_avg_fifteen_minutes float4 98 | ) 99 | RETURNS SETOF record 100 | AS 'MODULE_PATHNAME' 101 | LANGUAGE C; 102 | 103 | REVOKE ALL ON FUNCTION pg_sys_load_avg_info() FROM PUBLIC; 104 | GRANT EXECUTE ON FUNCTION pg_sys_load_avg_info() TO monitor_system_stats; 105 | 106 | -- network information function 107 | CREATE FUNCTION pg_sys_network_info( 108 | OUT interface_name text, 109 | OUT ip_address text, 110 | OUT tx_bytes int8, 111 | OUT tx_packets int8, 112 | OUT tx_errors int8, 113 | OUT tx_dropped int8, 114 | OUT rx_bytes int8, 115 | OUT rx_packets int8, 116 | OUT rx_errors int8, 117 | OUT rx_dropped int8, 118 | OUT link_speed_mbps int 119 | ) 120 | RETURNS SETOF record 121 | AS 'MODULE_PATHNAME' 122 | LANGUAGE C; 123 | 124 | REVOKE ALL ON FUNCTION pg_sys_network_info() FROM PUBLIC; 125 | GRANT EXECUTE ON FUNCTION pg_sys_network_info() TO monitor_system_stats; 126 | 127 | -- CPU and memory information by process id or name 128 | CREATE FUNCTION pg_sys_cpu_memory_by_process( 129 | OUT pid int, 130 | OUT name text, 131 | OUT running_since_seconds int8, 132 | OUT cpu_usage float4, 133 | OUT memory_usage float4, 134 | OUT memory_bytes int8 135 | ) 136 | RETURNS SETOF record 137 | AS 'MODULE_PATHNAME' 138 | LANGUAGE C; 139 | 140 | REVOKE ALL ON FUNCTION pg_sys_cpu_memory_by_process() FROM PUBLIC; 141 | GRANT EXECUTE ON FUNCTION pg_sys_cpu_memory_by_process() TO monitor_system_stats; 142 | 143 | -- Disk information function 144 | CREATE FUNCTION pg_sys_disk_info( 145 | OUT mount_point text, 146 | OUT file_system text, 147 | OUT drive_letter text, 148 | OUT drive_type int, 149 | OUT file_system_type text, 150 | OUT total_space int8, 151 | OUT used_space int8, 152 | OUT free_space int8, 153 | OUT total_inodes int8, 154 | OUT used_inodes int8, 155 | OUT free_inodes int8 156 | ) 157 | RETURNS SETOF record 158 | AS 'MODULE_PATHNAME' 159 | LANGUAGE C; 160 | 161 | REVOKE ALL ON FUNCTION pg_sys_disk_info() FROM PUBLIC; 162 | GRANT EXECUTE ON FUNCTION pg_sys_disk_info() TO monitor_system_stats; 163 | 164 | -- process information function 165 | CREATE FUNCTION pg_sys_process_info( 166 | OUT total_processes int, 167 | OUT running_processes int, 168 | OUT sleeping_processes int, 169 | OUT stopped_processes int, 170 | OUT zombie_processes int 171 | ) 172 | RETURNS SETOF record 173 | AS 'MODULE_PATHNAME' 174 | LANGUAGE C; 175 | 176 | REVOKE ALL ON FUNCTION pg_sys_process_info() FROM PUBLIC; 177 | GRANT EXECUTE ON FUNCTION pg_sys_process_info() TO monitor_system_stats; 178 | 179 | -- CPU usage information function 180 | -- This function will fetch the time spent in percentage by CPU in each mode 181 | -- as described by arguments 182 | CREATE FUNCTION pg_sys_cpu_usage_info( 183 | OUT usermode_normal_process_percent float4, 184 | OUT usermode_niced_process_percent float4, 185 | OUT kernelmode_process_percent float4, 186 | OUT idle_mode_percent float4, 187 | OUT IO_completion_percent float4, 188 | OUT servicing_irq_percent float4, 189 | OUT servicing_softirq_percent float4, 190 | OUT user_time_percent float4, 191 | OUT processor_time_percent float4, 192 | OUT privileged_time_percent float4, 193 | OUT interrupt_time_percent float4 194 | ) 195 | RETURNS SETOF record 196 | AS 'MODULE_PATHNAME' 197 | LANGUAGE C; 198 | 199 | REVOKE ALL ON FUNCTION pg_sys_cpu_usage_info() FROM PUBLIC; 200 | GRANT EXECUTE ON FUNCTION pg_sys_cpu_usage_info() TO monitor_system_stats; 201 | 202 | -- IO analysis information function 203 | CREATE FUNCTION pg_sys_io_analysis_info( 204 | OUT device_name text, 205 | OUT total_reads int8, 206 | OUT total_writes int8, 207 | OUT read_bytes int8, 208 | OUT write_bytes int8, 209 | OUT read_time_ms int8, 210 | OUT write_time_ms int8 211 | ) 212 | RETURNS SETOF record 213 | AS 'MODULE_PATHNAME' 214 | LANGUAGE C; 215 | 216 | REVOKE ALL ON FUNCTION pg_sys_io_analysis_info() FROM PUBLIC; 217 | GRANT EXECUTE ON FUNCTION pg_sys_io_analysis_info() TO monitor_system_stats; 218 | 219 | 220 | -------------------------------------------------------------------------------- /system_stats--2.0--3.0.sql: -------------------------------------------------------------------------------- 1 | -- No function has changed 2 | -------------------------------------------------------------------------------- /system_stats--2.0.sql: -------------------------------------------------------------------------------- 1 | /* system statistics extension */ 2 | 3 | -- complain if script is sourced in psql, rather than via CREATE EXTENSION 4 | \echo Use "CREATE EXTENSION system_stats" to load this file. \quit 5 | 6 | -- role to be assigned while executing functions of system stats 7 | -- before creating role, check the role exists or not. It may possible 8 | -- that user want to create extension in multiple database of same server 9 | DO $$ 10 | BEGIN 11 | IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'monitor_system_stats') THEN 12 | CREATE ROLE monitor_system_stats WITH 13 | NOLOGIN 14 | NOSUPERUSER 15 | NOCREATEDB 16 | NOCREATEROLE 17 | INHERIT 18 | NOREPLICATION 19 | CONNECTION LIMIT -1; 20 | END IF; 21 | END 22 | $$; 23 | 24 | -- Operating system information function 25 | CREATE FUNCTION pg_sys_os_info( 26 | OUT name text, 27 | OUT version text, 28 | OUT host_name text, 29 | OUT domain_name text, 30 | OUT handle_count int, 31 | OUT process_count int, 32 | OUT thread_count int, 33 | OUT architecture text, 34 | OUT last_bootup_time text, 35 | OUT os_up_since_seconds int 36 | ) 37 | RETURNS SETOF record 38 | AS 'MODULE_PATHNAME' 39 | LANGUAGE C; 40 | 41 | REVOKE ALL ON FUNCTION pg_sys_os_info() FROM PUBLIC; 42 | GRANT EXECUTE ON FUNCTION pg_sys_os_info() TO monitor_system_stats; 43 | 44 | -- System CPU information function 45 | CREATE FUNCTION pg_sys_cpu_info( 46 | OUT vendor text, 47 | OUT description text, 48 | OUT model_name text, 49 | OUT processor_type int, 50 | OUT logical_processor int, 51 | OUT physical_processor int, 52 | OUT no_of_cores int, 53 | OUT architecture text, 54 | OUT clock_speed_hz int8, 55 | OUT cpu_type text, 56 | OUT cpu_family text, 57 | OUT byte_order text, 58 | OUT l1dcache_size int, 59 | OUT l1icache_size int, 60 | OUT l2cache_size int, 61 | OUT l3cache_size int 62 | ) 63 | RETURNS SETOF record 64 | AS 'MODULE_PATHNAME' 65 | LANGUAGE C; 66 | 67 | REVOKE ALL ON FUNCTION pg_sys_cpu_info() FROM PUBLIC; 68 | GRANT EXECUTE ON FUNCTION pg_sys_cpu_info() TO monitor_system_stats; 69 | 70 | -- Memory information function 71 | CREATE FUNCTION pg_sys_memory_info( 72 | OUT total_memory int8, 73 | OUT used_memory int8, 74 | OUT free_memory int8, 75 | OUT swap_total int8, 76 | OUT swap_used int8, 77 | OUT swap_free int8, 78 | OUT cache_total int8, 79 | OUT kernel_total int8, 80 | OUT kernel_paged int8, 81 | OUT kernel_non_paged int8, 82 | OUT total_page_file int8, 83 | OUT avail_page_file int8 84 | ) 85 | RETURNS SETOF record 86 | AS 'MODULE_PATHNAME' 87 | LANGUAGE C; 88 | 89 | REVOKE ALL ON FUNCTION pg_sys_memory_info() FROM PUBLIC; 90 | GRANT EXECUTE ON FUNCTION pg_sys_memory_info() TO monitor_system_stats; 91 | 92 | -- Load average information function 93 | CREATE FUNCTION pg_sys_load_avg_info( 94 | OUT load_avg_one_minute float4, 95 | OUT load_avg_five_minutes float4, 96 | OUT load_avg_ten_minutes float4, 97 | OUT load_avg_fifteen_minutes float4 98 | ) 99 | RETURNS SETOF record 100 | AS 'MODULE_PATHNAME' 101 | LANGUAGE C; 102 | 103 | REVOKE ALL ON FUNCTION pg_sys_load_avg_info() FROM PUBLIC; 104 | GRANT EXECUTE ON FUNCTION pg_sys_load_avg_info() TO monitor_system_stats; 105 | 106 | -- network information function 107 | CREATE FUNCTION pg_sys_network_info( 108 | OUT interface_name text, 109 | OUT ip_address text, 110 | OUT tx_bytes int8, 111 | OUT tx_packets int8, 112 | OUT tx_errors int8, 113 | OUT tx_dropped int8, 114 | OUT rx_bytes int8, 115 | OUT rx_packets int8, 116 | OUT rx_errors int8, 117 | OUT rx_dropped int8, 118 | OUT link_speed_mbps int 119 | ) 120 | RETURNS SETOF record 121 | AS 'MODULE_PATHNAME' 122 | LANGUAGE C; 123 | 124 | REVOKE ALL ON FUNCTION pg_sys_network_info() FROM PUBLIC; 125 | GRANT EXECUTE ON FUNCTION pg_sys_network_info() TO monitor_system_stats; 126 | 127 | -- CPU and memory information by process id or name 128 | CREATE FUNCTION pg_sys_cpu_memory_by_process( 129 | OUT pid int, 130 | OUT name text, 131 | OUT running_since_seconds int8, 132 | OUT cpu_usage float4, 133 | OUT memory_usage float4, 134 | OUT memory_bytes int8 135 | ) 136 | RETURNS SETOF record 137 | AS 'MODULE_PATHNAME' 138 | LANGUAGE C; 139 | 140 | REVOKE ALL ON FUNCTION pg_sys_cpu_memory_by_process() FROM PUBLIC; 141 | GRANT EXECUTE ON FUNCTION pg_sys_cpu_memory_by_process() TO monitor_system_stats; 142 | 143 | -- Disk information function 144 | CREATE FUNCTION pg_sys_disk_info( 145 | OUT mount_point text, 146 | OUT file_system text, 147 | OUT drive_letter text, 148 | OUT drive_type int, 149 | OUT file_system_type text, 150 | OUT total_space int8, 151 | OUT used_space int8, 152 | OUT free_space int8, 153 | OUT total_inodes int8, 154 | OUT used_inodes int8, 155 | OUT free_inodes int8 156 | ) 157 | RETURNS SETOF record 158 | AS 'MODULE_PATHNAME' 159 | LANGUAGE C; 160 | 161 | REVOKE ALL ON FUNCTION pg_sys_disk_info() FROM PUBLIC; 162 | GRANT EXECUTE ON FUNCTION pg_sys_disk_info() TO monitor_system_stats; 163 | 164 | -- process information function 165 | CREATE FUNCTION pg_sys_process_info( 166 | OUT total_processes int, 167 | OUT running_processes int, 168 | OUT sleeping_processes int, 169 | OUT stopped_processes int, 170 | OUT zombie_processes int 171 | ) 172 | RETURNS SETOF record 173 | AS 'MODULE_PATHNAME' 174 | LANGUAGE C; 175 | 176 | REVOKE ALL ON FUNCTION pg_sys_process_info() FROM PUBLIC; 177 | GRANT EXECUTE ON FUNCTION pg_sys_process_info() TO monitor_system_stats; 178 | 179 | -- CPU usage information function 180 | -- This function will fetch the time spent in percentage by CPU in each mode 181 | -- as described by arguments 182 | CREATE FUNCTION pg_sys_cpu_usage_info( 183 | OUT usermode_normal_process_percent float4, 184 | OUT usermode_niced_process_percent float4, 185 | OUT kernelmode_process_percent float4, 186 | OUT idle_mode_percent float4, 187 | OUT IO_completion_percent float4, 188 | OUT servicing_irq_percent float4, 189 | OUT servicing_softirq_percent float4, 190 | OUT user_time_percent float4, 191 | OUT processor_time_percent float4, 192 | OUT privileged_time_percent float4, 193 | OUT interrupt_time_percent float4 194 | ) 195 | RETURNS SETOF record 196 | AS 'MODULE_PATHNAME' 197 | LANGUAGE C; 198 | 199 | REVOKE ALL ON FUNCTION pg_sys_cpu_usage_info() FROM PUBLIC; 200 | GRANT EXECUTE ON FUNCTION pg_sys_cpu_usage_info() TO monitor_system_stats; 201 | 202 | -- IO analysis information function 203 | CREATE FUNCTION pg_sys_io_analysis_info( 204 | OUT device_name text, 205 | OUT total_reads int8, 206 | OUT total_writes int8, 207 | OUT read_bytes int8, 208 | OUT write_bytes int8, 209 | OUT read_time_ms int8, 210 | OUT write_time_ms int8 211 | ) 212 | RETURNS SETOF record 213 | AS 'MODULE_PATHNAME' 214 | LANGUAGE C; 215 | 216 | REVOKE ALL ON FUNCTION pg_sys_io_analysis_info() FROM PUBLIC; 217 | GRANT EXECUTE ON FUNCTION pg_sys_io_analysis_info() TO monitor_system_stats; 218 | 219 | 220 | -------------------------------------------------------------------------------- /system_stats--3.0.sql: -------------------------------------------------------------------------------- 1 | /* system statistics extension */ 2 | 3 | -- complain if script is sourced in psql, rather than via CREATE EXTENSION 4 | \echo Use "CREATE EXTENSION system_stats" to load this file. \quit 5 | 6 | -- role to be assigned while executing functions of system stats 7 | -- before creating role, check the role exists or not. It may possible 8 | -- that user want to create extension in multiple database of same server 9 | DO $$ 10 | BEGIN 11 | IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'monitor_system_stats') THEN 12 | CREATE ROLE monitor_system_stats WITH 13 | NOLOGIN 14 | NOSUPERUSER 15 | NOCREATEDB 16 | NOCREATEROLE 17 | INHERIT 18 | NOREPLICATION 19 | CONNECTION LIMIT -1; 20 | END IF; 21 | END 22 | $$; 23 | 24 | -- Operating system information function 25 | CREATE FUNCTION pg_sys_os_info( 26 | OUT name text, 27 | OUT version text, 28 | OUT host_name text, 29 | OUT domain_name text, 30 | OUT handle_count int, 31 | OUT process_count int, 32 | OUT thread_count int, 33 | OUT architecture text, 34 | OUT last_bootup_time text, 35 | OUT os_up_since_seconds int 36 | ) 37 | RETURNS SETOF record 38 | AS 'MODULE_PATHNAME' 39 | LANGUAGE C; 40 | 41 | REVOKE ALL ON FUNCTION pg_sys_os_info() FROM PUBLIC; 42 | GRANT EXECUTE ON FUNCTION pg_sys_os_info() TO monitor_system_stats; 43 | 44 | -- System CPU information function 45 | CREATE FUNCTION pg_sys_cpu_info( 46 | OUT vendor text, 47 | OUT description text, 48 | OUT model_name text, 49 | OUT processor_type int, 50 | OUT logical_processor int, 51 | OUT physical_processor int, 52 | OUT no_of_cores int, 53 | OUT architecture text, 54 | OUT clock_speed_hz int8, 55 | OUT cpu_type text, 56 | OUT cpu_family text, 57 | OUT byte_order text, 58 | OUT l1dcache_size int, 59 | OUT l1icache_size int, 60 | OUT l2cache_size int, 61 | OUT l3cache_size int 62 | ) 63 | RETURNS SETOF record 64 | AS 'MODULE_PATHNAME' 65 | LANGUAGE C; 66 | 67 | REVOKE ALL ON FUNCTION pg_sys_cpu_info() FROM PUBLIC; 68 | GRANT EXECUTE ON FUNCTION pg_sys_cpu_info() TO monitor_system_stats; 69 | 70 | -- Memory information function 71 | CREATE FUNCTION pg_sys_memory_info( 72 | OUT total_memory int8, 73 | OUT used_memory int8, 74 | OUT free_memory int8, 75 | OUT swap_total int8, 76 | OUT swap_used int8, 77 | OUT swap_free int8, 78 | OUT cache_total int8, 79 | OUT kernel_total int8, 80 | OUT kernel_paged int8, 81 | OUT kernel_non_paged int8, 82 | OUT total_page_file int8, 83 | OUT avail_page_file int8 84 | ) 85 | RETURNS SETOF record 86 | AS 'MODULE_PATHNAME' 87 | LANGUAGE C; 88 | 89 | REVOKE ALL ON FUNCTION pg_sys_memory_info() FROM PUBLIC; 90 | GRANT EXECUTE ON FUNCTION pg_sys_memory_info() TO monitor_system_stats; 91 | 92 | -- Load average information function 93 | CREATE FUNCTION pg_sys_load_avg_info( 94 | OUT load_avg_one_minute float4, 95 | OUT load_avg_five_minutes float4, 96 | OUT load_avg_ten_minutes float4, 97 | OUT load_avg_fifteen_minutes float4 98 | ) 99 | RETURNS SETOF record 100 | AS 'MODULE_PATHNAME' 101 | LANGUAGE C; 102 | 103 | REVOKE ALL ON FUNCTION pg_sys_load_avg_info() FROM PUBLIC; 104 | GRANT EXECUTE ON FUNCTION pg_sys_load_avg_info() TO monitor_system_stats; 105 | 106 | -- network information function 107 | CREATE FUNCTION pg_sys_network_info( 108 | OUT interface_name text, 109 | OUT ip_address text, 110 | OUT tx_bytes int8, 111 | OUT tx_packets int8, 112 | OUT tx_errors int8, 113 | OUT tx_dropped int8, 114 | OUT rx_bytes int8, 115 | OUT rx_packets int8, 116 | OUT rx_errors int8, 117 | OUT rx_dropped int8, 118 | OUT link_speed_mbps int 119 | ) 120 | RETURNS SETOF record 121 | AS 'MODULE_PATHNAME' 122 | LANGUAGE C; 123 | 124 | REVOKE ALL ON FUNCTION pg_sys_network_info() FROM PUBLIC; 125 | GRANT EXECUTE ON FUNCTION pg_sys_network_info() TO monitor_system_stats; 126 | 127 | -- CPU and memory information by process id or name 128 | CREATE FUNCTION pg_sys_cpu_memory_by_process( 129 | OUT pid int, 130 | OUT name text, 131 | OUT running_since_seconds int8, 132 | OUT cpu_usage float4, 133 | OUT memory_usage float4, 134 | OUT memory_bytes int8 135 | ) 136 | RETURNS SETOF record 137 | AS 'MODULE_PATHNAME' 138 | LANGUAGE C; 139 | 140 | REVOKE ALL ON FUNCTION pg_sys_cpu_memory_by_process() FROM PUBLIC; 141 | GRANT EXECUTE ON FUNCTION pg_sys_cpu_memory_by_process() TO monitor_system_stats; 142 | 143 | -- Disk information function 144 | CREATE FUNCTION pg_sys_disk_info( 145 | OUT mount_point text, 146 | OUT file_system text, 147 | OUT drive_letter text, 148 | OUT drive_type int, 149 | OUT file_system_type text, 150 | OUT total_space int8, 151 | OUT used_space int8, 152 | OUT free_space int8, 153 | OUT total_inodes int8, 154 | OUT used_inodes int8, 155 | OUT free_inodes int8 156 | ) 157 | RETURNS SETOF record 158 | AS 'MODULE_PATHNAME' 159 | LANGUAGE C; 160 | 161 | REVOKE ALL ON FUNCTION pg_sys_disk_info() FROM PUBLIC; 162 | GRANT EXECUTE ON FUNCTION pg_sys_disk_info() TO monitor_system_stats; 163 | 164 | -- process information function 165 | CREATE FUNCTION pg_sys_process_info( 166 | OUT total_processes int, 167 | OUT running_processes int, 168 | OUT sleeping_processes int, 169 | OUT stopped_processes int, 170 | OUT zombie_processes int 171 | ) 172 | RETURNS SETOF record 173 | AS 'MODULE_PATHNAME' 174 | LANGUAGE C; 175 | 176 | REVOKE ALL ON FUNCTION pg_sys_process_info() FROM PUBLIC; 177 | GRANT EXECUTE ON FUNCTION pg_sys_process_info() TO monitor_system_stats; 178 | 179 | -- CPU usage information function 180 | -- This function will fetch the time spent in percentage by CPU in each mode 181 | -- as described by arguments 182 | CREATE FUNCTION pg_sys_cpu_usage_info( 183 | OUT usermode_normal_process_percent float4, 184 | OUT usermode_niced_process_percent float4, 185 | OUT kernelmode_process_percent float4, 186 | OUT idle_mode_percent float4, 187 | OUT IO_completion_percent float4, 188 | OUT servicing_irq_percent float4, 189 | OUT servicing_softirq_percent float4, 190 | OUT user_time_percent float4, 191 | OUT processor_time_percent float4, 192 | OUT privileged_time_percent float4, 193 | OUT interrupt_time_percent float4 194 | ) 195 | RETURNS SETOF record 196 | AS 'MODULE_PATHNAME' 197 | LANGUAGE C; 198 | 199 | REVOKE ALL ON FUNCTION pg_sys_cpu_usage_info() FROM PUBLIC; 200 | GRANT EXECUTE ON FUNCTION pg_sys_cpu_usage_info() TO monitor_system_stats; 201 | 202 | -- IO analysis information function 203 | CREATE FUNCTION pg_sys_io_analysis_info( 204 | OUT device_name text, 205 | OUT total_reads int8, 206 | OUT total_writes int8, 207 | OUT read_bytes int8, 208 | OUT write_bytes int8, 209 | OUT read_time_ms int8, 210 | OUT write_time_ms int8 211 | ) 212 | RETURNS SETOF record 213 | AS 'MODULE_PATHNAME' 214 | LANGUAGE C; 215 | 216 | REVOKE ALL ON FUNCTION pg_sys_io_analysis_info() FROM PUBLIC; 217 | GRANT EXECUTE ON FUNCTION pg_sys_io_analysis_info() TO monitor_system_stats; 218 | 219 | 220 | -------------------------------------------------------------------------------- /system_stats.control: -------------------------------------------------------------------------------- 1 | # system_stats extension 2 | comment = 'EnterpriseDB system statistics for PostgreSQL' 3 | default_version = '3.0' 4 | module_pathname = '$libdir/system_stats' 5 | relocatable = true 6 | -------------------------------------------------------------------------------- /system_stats.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * system_stats.h 3 | * Defined macros and function prototypes for system 4 | * statistics information 5 | * 6 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 7 | * 8 | *------------------------------------------------------------------------ 9 | */ 10 | #ifndef SYSTEM_STATS_H 11 | #define SYSTEM_STATS_H 12 | 13 | #ifdef WIN32 14 | #include 15 | #include 16 | #endif 17 | 18 | #include "access/tupdesc.h" 19 | #include "utils/tuplestore.h" 20 | #include "utils/builtins.h" 21 | 22 | /* prototypes for system disk information functions */ 23 | void ReadDiskInformation(Tuplestorestate *tupstore, TupleDesc tupdesc); 24 | 25 | /* prototypes for system IO analysis functions */ 26 | void ReadIOAnalysisInformation(Tuplestorestate *tupstore, TupleDesc tupdesc); 27 | 28 | /* prototypes for system CPU information functions */ 29 | void ReadCPUInformation(Tuplestorestate *tupstore, TupleDesc tupdesc); 30 | 31 | /* prototypes for system memory information functions */ 32 | void ReadMemoryInformation(Tuplestorestate *tupstore, TupleDesc tupdesc); 33 | 34 | /* prototypes for system load average information functions */ 35 | void ReadLoadAvgInformations(Tuplestorestate *tupstore, TupleDesc tupdesc); 36 | 37 | /* prototypes for operating system information functions */ 38 | void ReadOSInformations(Tuplestorestate *tupstore, TupleDesc tupdesc); 39 | 40 | /* prototypes for system CPU usage information functions */ 41 | void ReadCPUUsageStatistics(Tuplestorestate *tupstore, TupleDesc tupdesc); 42 | 43 | /* prototypes for system process information functions */ 44 | void ReadProcessInformations(Tuplestorestate *tupstore, TupleDesc tupdesc); 45 | 46 | /* prototypes for system network information functions */ 47 | void ReadNetworkInformations(Tuplestorestate *tupstore, TupleDesc tupdesc); 48 | 49 | /* prototypes for system network information functions */ 50 | void ReadCPUMemoryByProcess(Tuplestorestate *tupstore, TupleDesc tupdesc); 51 | 52 | #ifndef WIN32 53 | /* prototypes for common string manipulations and command execution functions */ 54 | bool stringIsNumber(char *str); 55 | char* lefttrimStr(char *); 56 | char* righttrimStr(char *); 57 | char* trimStr(char *); 58 | float fl_round(float val); 59 | bool read_process_status(int *active_processes, int *running_processes, 60 | int *sleeping_processes, int *stopped_processes, int *zombie_processes, int *total_threads); 61 | void ReadFileContent(const char *file_name, uint64 *data); 62 | 63 | /* prototypes for system disk information functions */ 64 | bool ignoreFileSystemTypes(char *fs_mnt); 65 | bool ignoreMountPoints(char *fs_mnt); 66 | 67 | /* prototypes for system memory information functions */ 68 | uint64_t ConvertToBytes(char *line_buf); 69 | #else 70 | void initialize_wmi_connection(); 71 | void uninitialize_wmi_connection(); 72 | void execute_init_query(); 73 | IEnumWbemClassObject* execute_query(BSTR query); 74 | int is_process_running(int pid); 75 | #endif 76 | 77 | /* read the the output of command in chunk of 1024 bytes */ 78 | #define READ_CHUNK_BYTES 1024 79 | #define MIN_BUFFER_SIZE 512 80 | #define MAX_BUFFER_SIZE 2048 81 | #define IS_EMPTY_STR(X) ((1 / (sizeof(X[0]) == 1)) && !(X[0])) 82 | #define PROC_FILE_SYSTEM_PATH "/proc" 83 | 84 | /* Macros for system disk information */ 85 | #define Natts_disk_info 11 86 | #define FILE_SYSTEM_MOUNT_FILE_NAME "/etc/mtab" 87 | #define IGNORE_MOUNT_POINTS_REGEX "^/(dev|proc|sys|run|snap|var/lib/docker/.+)($|/)" 88 | #define IGNORE_FILE_SYSTEM_TYPE_REGEX "^(autofs|binfmt_misc|bpf|cgroup2?|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|iso9660|mqueue|nsfs|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|selinuxfs|squashfs|sysfs|tracefs)$" 89 | #define Anum_disk_mount_point 0 90 | #define Anum_disk_file_system 1 91 | #define Anum_disk_drive_letter 2 92 | #define Anum_disk_drive_type 3 93 | #define Anum_disk_file_system_type 4 94 | #define Anum_disk_total_space 5 95 | #define Anum_disk_used_space 6 96 | #define Anum_disk_free_space 7 97 | #define Anum_disk_total_inodes 8 98 | #define Anum_disk_used_inodes 9 99 | #define Anum_disk_free_inodes 10 100 | 101 | /* Macros for system IO Analysis */ 102 | #define Natts_io_analysis_info 7 103 | #define DISK_IO_STATS_FILE_NAME "/proc/diskstats" 104 | #define Anum_device_name 0 105 | #define Anum_total_read 1 106 | #define Anum_total_write 2 107 | #define Anum_read_bytes 3 108 | #define Anum_write_bytes 4 109 | #define Anum_read_time_ms 5 110 | #define Anum_write_time_ms 6 111 | 112 | /* Macros for system CPU information */ 113 | #define Natts_cpu_info 16 114 | #define CPU_INFO_FILE_NAME "/proc/cpuinfo" 115 | #define Anum_cpu_vendor 0 116 | #define Anum_cpu_description 1 117 | #define Anum_model_name 2 118 | #define Anum_processor_type 3 119 | #define Anum_logical_processor 4 120 | #define Anum_physical_processor 5 121 | #define Anum_no_of_cores 6 122 | #define Anum_architecture 7 123 | #define Anum_cpu_clock_speed 8 124 | #define Anum_cpu_type 9 125 | #define Anum_cpu_family 10 126 | #define Anum_cpu_byte_order 11 127 | #define Anum_l1dcache_size 12 128 | #define Anum_l1icache_size 13 129 | #define Anum_l2cache_size 14 130 | #define Anum_l3cache_size 15 131 | 132 | /* Macros for Memory information */ 133 | #define MEMORY_READ_COUNT 5 134 | #define Natts_memory_info 12 135 | #define MEMORY_FILE_NAME "/proc/meminfo" 136 | #define Anum_total_memory 0 137 | #define Anum_used_memory 1 138 | #define Anum_free_memory 2 139 | #define Anum_swap_total_memory 3 140 | #define Anum_swap_used_memory 4 141 | #define Anum_swap_free_memory 5 142 | #define Anum_total_cache_memory 6 143 | #define Anum_kernel_total_memory 7 144 | #define Anum_kernel_paged_memory 8 145 | #define Anum_kernel_nonpaged_memory 9 146 | #define Anum_total_page_file 10 147 | #define Anum_avail_page_file 11 148 | 149 | /* Macros for load average information */ 150 | #define CPU_IO_LOAD_AVG_FILE "/proc/loadavg" 151 | #define Natts_load_avg_info 4 152 | #define Anum_load_avg_one_minute 0 153 | #define Anum_load_avg_five_minutes 1 154 | #define Anum_load_avg_ten_minutes 2 155 | #define Anum_load_avg_fifteen_minutes 3 156 | 157 | /* Macros for operating system information */ 158 | #define Natts_os_info 10 159 | #define OS_INFO_FILE_NAME "/etc/os-release" 160 | #define OS_DESC_SEARCH_TEXT "PRETTY_NAME=" 161 | #define OS_HANDLE_READ_FILE_PATH "/proc/sys/fs/file-nr" 162 | #define OS_BOOT_UP_SINCE_FILE_PATH "/proc/uptime" 163 | #define Anum_os_name 0 164 | #define Anum_os_version 1 165 | #define Anum_host_name 2 166 | #define Anum_domain_name 3 167 | #define Anum_os_handle_count 4 168 | #define Anum_os_process_count 5 169 | #define Anum_os_thread_count 6 170 | #define Anum_os_architecture 7 171 | #define Anum_os_boot_time 8 172 | #define Anum_os_up_since_seconds 9 173 | 174 | /* Macros for system CPU usage information */ 175 | #define Natts_cpu_usage_stats 11 176 | #define CPU_USAGE_STATS_FILENAME "/proc/stat" 177 | #define Anum_usermode_normal_process 0 178 | #define Anum_usermode_niced_process 1 179 | #define Anum_kernelmode_process 2 180 | #define Anum_idle_mode 3 181 | #define Anum_io_completion 4 182 | #define Anum_servicing_irq 5 183 | #define Anum_servicing_softirq 6 184 | #define Anum_percent_user_time 7 185 | #define Anum_percent_processor_time 8 186 | #define Anum_percent_privileged_time 9 187 | #define Anum_percent_interrupt_time 10 188 | 189 | /* Macros for system processes information */ 190 | #define Natts_process_info 5 191 | #define Anum_no_of_total_processes 0 192 | #define Anum_no_of_running_processes 1 193 | #define Anum_no_of_sleeping_processes 2 194 | #define Anum_no_of_stopped_processes 3 195 | #define Anum_no_of_zombie_processes 4 196 | 197 | /* Macros for network information */ 198 | #define Natts_network_info 11 199 | #define Anum_net_interface_name 0 200 | #define Anum_net_ipv4_address 1 201 | #define Anum_net_tx_bytes 2 202 | #define Anum_net_tx_packets 3 203 | #define Anum_net_tx_errors 4 204 | #define Anum_net_tx_dropped 5 205 | #define Anum_net_rx_bytes 6 206 | #define Anum_net_rx_packets 7 207 | #define Anum_net_rx_errors 8 208 | #define Anum_net_rx_dropped 9 209 | #define Anum_net_speed_mbps 10 210 | 211 | /* Macros for cpu and memory information 212 | * by process*/ 213 | #define Natts_cpu_memory_info_by_process 6 214 | #define Anum_process_pid 0 215 | #define Anum_process_name 1 216 | #define Anum_process_running_since 2 217 | #define Anum_percent_cpu_usage 3 218 | #define Anum_percent_memory_usage 4 219 | #define Anum_process_memory_bytes 5 220 | 221 | #endif // SYSTEM_STATS_H 222 | -------------------------------------------------------------------------------- /system_stats.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.1000 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "system_stats", "system_stats.vcxproj", "{2A658257-D490-4383-9686-6DDDE92BDD06}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {2A658257-D490-4383-9686-6DDDE92BDD06}.Debug|x64.ActiveCfg = Debug|x64 17 | {2A658257-D490-4383-9686-6DDDE92BDD06}.Debug|x64.Build.0 = Debug|x64 18 | {2A658257-D490-4383-9686-6DDDE92BDD06}.Debug|x86.ActiveCfg = Debug|Win32 19 | {2A658257-D490-4383-9686-6DDDE92BDD06}.Debug|x86.Build.0 = Debug|Win32 20 | {2A658257-D490-4383-9686-6DDDE92BDD06}.Release|x64.ActiveCfg = Release|x64 21 | {2A658257-D490-4383-9686-6DDDE92BDD06}.Release|x64.Build.0 = Release|x64 22 | {2A658257-D490-4383-9686-6DDDE92BDD06}.Release|x86.ActiveCfg = Release|Win32 23 | {2A658257-D490-4383-9686-6DDDE92BDD06}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {50FF909D-6DCA-4E6D-B794-16EEEEDC77F4} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /system_stats.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {2A658257-D490-4383-9686-6DDDE92BDD06} 24 | systemstats 25 | 10.0.17763.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v141 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v141 38 | true 39 | MultiByte 40 | 41 | 42 | DynamicLibrary 43 | true 44 | v141 45 | MultiByte 46 | 47 | 48 | DynamicLibrary 49 | false 50 | v141 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | false 74 | 75 | 76 | false 77 | 78 | 79 | 80 | Level3 81 | Disabled 82 | true 83 | true 84 | 85 | 86 | Console 87 | 88 | 89 | 90 | 91 | Level3 92 | Disabled 93 | true 94 | true 95 | false 96 | CompileAsC 97 | .\;$(PG_INCLUDE_DIR)\server\port\win32_msvc;$(PG_INCLUDE_DIR)\server\port\win32;$(PG_INCLUDE_DIR)\server;$(PG_INCLUDE_DIR);$(PG_INCLUDE_DIR)\port\win32_msvc;$(PG_INCLUDE_DIR)\port\win32;%(AdditionalIncludeDirectories) 98 | 99 | 100 | Console 101 | $(PG_LIB_DIR)\postgres.lib;wbemuuid.lib;%(AdditionalDependencies) 102 | $(PG_LIB_DIR);%(AdditionalLibraryDirectories) 103 | 104 | 105 | 106 | 107 | Level3 108 | MaxSpeed 109 | true 110 | true 111 | true 112 | true 113 | 114 | 115 | Console 116 | true 117 | true 118 | 119 | 120 | 121 | 122 | Level3 123 | MaxSpeed 124 | true 125 | true 126 | true 127 | true 128 | false 129 | CompileAsC 130 | .\;$(PG_INCLUDE_DIR)\server\port\win32_msvc;$(PG_INCLUDE_DIR)\server\port\win32;$(PG_INCLUDE_DIR)\server;$(PG_INCLUDE_DIR);$(PG_INCLUDE_DIR)\port\win32_msvc;$(PG_INCLUDE_DIR)\port\win32;%(AdditionalIncludeDirectories) 131 | 132 | 133 | Console 134 | true 135 | true 136 | $(PG_LIB_DIR)\postgres.lib;wbemuuid.lib;%(AdditionalDependencies) 137 | $(PG_LIB_DIR);%(AdditionalLibraryDirectories) 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /system_stats.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | 56 | 57 | Header Files 58 | 59 | 60 | -------------------------------------------------------------------------------- /uninstall_system_stats.sql: -------------------------------------------------------------------------------- 1 | DROP FUNCTION pg_sys_cpu_info(); 2 | DROP FUNCTION pg_sys_cpu_usage_info(); 3 | DROP FUNCTION pg_sys_memory_info(); 4 | DROP FUNCTION pg_sys_io_analysis_info(); 5 | DROP FUNCTION pg_sys_disk_info(); 6 | DROP FUNCTION pg_sys_load_avg_info(); 7 | DROP FUNCTION pg_sys_os_info(); 8 | DROP FUNCTION pg_sys_process_info(); 9 | DROP FUNCTION pg_sys_network_info(); 10 | DROP FUNCTION pg_sys_cpu_memory_by_process(); 11 | -------------------------------------------------------------------------------- /windows/cpu_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * cpu_info.c 3 | * System CPU information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | 16 | void ReadCPUInformation(Tuplestorestate *tupstore, TupleDesc tupdesc) 17 | { 18 | Datum values[Natts_cpu_info]; 19 | bool nulls[Natts_cpu_info]; 20 | int no_physical_cpus = 0; 21 | 22 | memset(nulls, 0, sizeof(nulls)); 23 | 24 | // result code from COM calls from program 25 | HRESULT hres = 0; 26 | IEnumWbemClassObject *results = NULL; 27 | BSTR query = SysAllocString(L"SELECT Caption, Manufacturer, Name, ProcessorType, Architecture,MaxClockSpeed, L2CacheSize, L3CacheSize, NumberOfCores, NumberOfLogicalProcessors FROM Win32_Processor"); 28 | 29 | // issue a WMI query 30 | results = execute_query(query); 31 | 32 | /* list the query results */ 33 | if (results != NULL) 34 | { 35 | IWbemClassObject *result = NULL; 36 | ULONG returnedCount = 0; 37 | 38 | // enumerate the retrieved objects 39 | while ((hres = results->lpVtbl->Next(results, WBEM_INFINITE, 1, &result, &returnedCount)) == S_OK) 40 | { 41 | VARIANT query_result; 42 | int wstr_length = 0; 43 | char *dst = NULL; 44 | size_t charsConverted = 0; 45 | 46 | no_physical_cpus++; 47 | 48 | hres = result->lpVtbl->Get(result, L"Caption", 0, &query_result, 0, 0); 49 | if (FAILED(hres)) 50 | nulls[Anum_cpu_description] = true; 51 | else 52 | { 53 | wstr_length = 0; 54 | charsConverted = 0; 55 | wstr_length = SysStringLen(query_result.bstrVal); 56 | if (wstr_length == 0) 57 | nulls[Anum_cpu_description] = true; 58 | else 59 | { 60 | dst = (char *)malloc(wstr_length + 10); 61 | memset(dst, 0x00, (wstr_length + 10)); 62 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 63 | values[Anum_cpu_description] = CStringGetTextDatum(dst); 64 | free(dst); 65 | } 66 | VariantClear(&query_result); 67 | } 68 | 69 | hres = result->lpVtbl->Get(result, L"Manufacturer", 0, &query_result, 0, 0); 70 | if (FAILED(hres)) 71 | nulls[Anum_cpu_vendor] = true; 72 | else 73 | { 74 | wstr_length = 0; 75 | charsConverted = 0; 76 | wstr_length = SysStringLen(query_result.bstrVal); 77 | if (wstr_length == 0) 78 | nulls[Anum_cpu_vendor] = true; 79 | else 80 | { 81 | dst = (char *)malloc(wstr_length + 10); 82 | memset(dst, 0x00, (wstr_length + 10)); 83 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 84 | values[Anum_cpu_vendor] = CStringGetTextDatum(dst); 85 | free(dst); 86 | } 87 | VariantClear(&query_result); 88 | } 89 | 90 | hres = result->lpVtbl->Get(result, L"Name", 0, &query_result, 0, 0); 91 | if (FAILED(hres)) 92 | nulls[Anum_model_name] = true; 93 | else 94 | { 95 | wstr_length = 0; 96 | charsConverted = 0; 97 | wstr_length = SysStringLen(query_result.bstrVal); 98 | if (wstr_length == 0) 99 | nulls[Anum_model_name] = true; 100 | else 101 | { 102 | dst = (char *)malloc(wstr_length + 10); 103 | memset(dst, 0x00, (wstr_length + 10)); 104 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 105 | values[Anum_model_name] = CStringGetTextDatum(dst); 106 | free(dst); 107 | } 108 | VariantClear(&query_result); 109 | } 110 | 111 | hres = result->lpVtbl->Get(result, L"ProcessorType", 0, &query_result, 0, 0); 112 | if (FAILED(hres)) 113 | nulls[Anum_processor_type] = true; 114 | else { 115 | values[Anum_processor_type] = Int32GetDatum(query_result.intVal); 116 | VariantClear(&query_result); 117 | } 118 | 119 | hres = result->lpVtbl->Get(result, L"MaxClockSpeed", 0, &query_result, 0, 0); 120 | if (FAILED(hres)) 121 | nulls[Anum_cpu_clock_speed] = true; 122 | else 123 | { 124 | /* convert MHz to Hz */ 125 | uint64 max_clock_speed = (uint64)((uint64)(query_result.intVal) * (uint64)1000000); 126 | values[Anum_cpu_clock_speed] = UInt64GetDatum(max_clock_speed); 127 | VariantClear(&query_result); 128 | } 129 | 130 | hres = result->lpVtbl->Get(result, L"Architecture", 0, &query_result, 0, 0); 131 | if (FAILED(hres)) 132 | nulls[Anum_architecture] = true; 133 | else 134 | { 135 | int val = query_result.intVal; 136 | char arch[MAXPGPATH]; 137 | memset(arch, 0x00, MAXPGPATH); 138 | snprintf(arch, MAXPGPATH, "%d", val); 139 | values[Anum_architecture] = CStringGetTextDatum(arch); 140 | VariantClear(&query_result); 141 | } 142 | 143 | hres = result->lpVtbl->Get(result, L"L2CacheSize", 0, &query_result, 0, 0); 144 | if (FAILED(hres)) 145 | nulls[Anum_l2cache_size] = true; 146 | else { 147 | values[Anum_l2cache_size] = Int32GetDatum(query_result.intVal); 148 | VariantClear(&query_result); 149 | } 150 | 151 | hres = result->lpVtbl->Get(result, L"L3CacheSize", 0, &query_result, 0, 0); 152 | if (FAILED(hres)) 153 | nulls[Anum_l3cache_size] = true; 154 | else { 155 | values[Anum_l3cache_size] = Int32GetDatum(query_result.intVal); 156 | VariantClear(&query_result); 157 | } 158 | 159 | hres = result->lpVtbl->Get(result, L"NumberOfCores", 0, &query_result, 0, 0); 160 | if (FAILED(hres)) 161 | nulls[Anum_no_of_cores] = true; 162 | else { 163 | values[Anum_no_of_cores] = Int32GetDatum(query_result.intVal); 164 | VariantClear(&query_result); 165 | } 166 | 167 | hres = result->lpVtbl->Get(result, L"NumberOfLogicalProcessors", 0, &query_result, 0, 0); 168 | if (FAILED(hres)) 169 | nulls[Anum_logical_processor] = true; 170 | else { 171 | values[Anum_logical_processor] = Int32GetDatum(query_result.intVal); 172 | VariantClear(&query_result); 173 | } 174 | 175 | /* release the current result object */ 176 | result->lpVtbl->Release(result); 177 | } 178 | 179 | nulls[Anum_l1dcache_size] = true; 180 | nulls[Anum_l1icache_size] = true; 181 | nulls[Anum_cpu_type] = true; 182 | nulls[Anum_cpu_family] = true; 183 | nulls[Anum_cpu_byte_order] = true; 184 | values[Anum_physical_processor] = Int32GetDatum(no_physical_cpus); 185 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 186 | 187 | /* release results set */ 188 | results->lpVtbl->Release(results); 189 | } 190 | else 191 | ereport(DEBUG1, (errmsg("[ReadCPUInformation]: Failed to get query result"))); 192 | 193 | SysFreeString(query); 194 | } 195 | -------------------------------------------------------------------------------- /windows/cpu_memory_by_process.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * cpu_memory_by_process.c 3 | * CPU and memory usage by process id or name 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | 16 | void ReadCPUMemoryByProcess(Tuplestorestate *tupstore, TupleDesc tupdesc) 17 | { 18 | Datum values[Natts_cpu_memory_info_by_process]; 19 | bool nulls[Natts_cpu_memory_info_by_process]; 20 | MEMORYSTATUSEX statex; 21 | uint64 total_physical_memory = 0; 22 | 23 | memset(nulls, 0, sizeof(nulls)); 24 | 25 | statex.dwLength = sizeof(statex); 26 | 27 | if (GlobalMemoryStatusEx(&statex) == 0) 28 | { 29 | LPVOID lpMsgBuf; 30 | DWORD dw = GetLastError(); 31 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 32 | NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL); 33 | ereport(DEBUG1, (errmsg("Error while getting memory information: %s", (char *)lpMsgBuf))); 34 | LocalFree(lpMsgBuf); 35 | } 36 | 37 | total_physical_memory = (uint64)statex.ullTotalPhys; 38 | 39 | // result code from COM calls from program 40 | HRESULT hres = 0; 41 | IEnumWbemClassObject *results = NULL; 42 | BSTR query = SysAllocString(L"SELECT * FROM Win32_PerfFormattedData_PerfProc_Process"); 43 | 44 | // issue a WMI query 45 | results = execute_query(query); 46 | 47 | /* list the query results */ 48 | if (results != NULL) 49 | { 50 | IWbemClassObject *result = NULL; 51 | ULONG returnedCount = 0; 52 | 53 | // enumerate the retrieved objects 54 | while ((hres = results->lpVtbl->Next(results, WBEM_INFINITE, 1, &result, &returnedCount)) == S_OK) 55 | { 56 | VARIANT query_result; 57 | 58 | int wstr_length = 0; 59 | char *dst = NULL; 60 | size_t charsConverted = 0; 61 | 62 | /* Get the value from query output */ 63 | hres = result->lpVtbl->Get(result, L"IDProcess", 0, &query_result, 0, 0); 64 | if (FAILED(hres)) 65 | nulls[Anum_process_pid] = true; 66 | else { 67 | values[Anum_process_pid] = Int32GetDatum(query_result.intVal); 68 | VariantClear(&query_result); 69 | } 70 | 71 | hres = result->lpVtbl->Get(result, L"Name", 0, &query_result, 0, 0); 72 | if (FAILED(hres)) 73 | nulls[Anum_process_name] = true; 74 | else 75 | { 76 | wstr_length = 0; 77 | charsConverted = 0; 78 | wstr_length = SysStringLen(query_result.bstrVal); 79 | if (wstr_length == 0) 80 | nulls[Anum_process_name] = true; 81 | else 82 | { 83 | dst = (char *)malloc(wstr_length + 10); 84 | memset(dst, 0x00, (wstr_length + 10)); 85 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 86 | values[Anum_process_name] = CStringGetTextDatum(dst); 87 | free(dst); 88 | } 89 | VariantClear(&query_result); 90 | } 91 | 92 | hres = result->lpVtbl->Get(result, L"ElapsedTime", 0, &query_result, 0, 0); 93 | if (FAILED(hres)) 94 | nulls[Anum_process_running_since] = true; 95 | else 96 | { 97 | wstr_length = 0; 98 | charsConverted = 0; 99 | wstr_length = SysStringLen(query_result.bstrVal); 100 | if (wstr_length == 0) 101 | nulls[Anum_process_running_since] = true; 102 | else 103 | { 104 | dst = (char *)malloc(wstr_length + 10); 105 | memset(dst, 0x00, (wstr_length + 10)); 106 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 107 | long long val = strtoll(dst, NULL, 10); 108 | values[Anum_process_running_since] = UInt64GetDatum(val); 109 | free(dst); 110 | } 111 | VariantClear(&query_result); 112 | } 113 | 114 | hres = result->lpVtbl->Get(result, L"PercentProcessorTime", 0, &query_result, 0, 0); 115 | if (FAILED(hres)) 116 | nulls[Anum_percent_cpu_usage] = true; 117 | else 118 | { 119 | wstr_length = 0; 120 | charsConverted = 0; 121 | wstr_length = SysStringLen(query_result.bstrVal); 122 | if (wstr_length == 0) 123 | nulls[Anum_percent_cpu_usage] = true; 124 | else 125 | { 126 | dst = (char *)malloc(wstr_length + 10); 127 | memset(dst, 0x00, (wstr_length + 10)); 128 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 129 | long long val = strtoll(dst, NULL, 10); 130 | float4 cpu_usage_per = (float4)val; 131 | values[Anum_percent_cpu_usage] = Float4GetDatum(cpu_usage_per); 132 | free(dst); 133 | } 134 | VariantClear(&query_result); 135 | } 136 | 137 | hres = result->lpVtbl->Get(result, L"WorkingSetPrivate", 0, &query_result, 0, 0); 138 | if (FAILED(hres)) 139 | nulls[Anum_percent_memory_usage] = true; 140 | else 141 | { 142 | wstr_length = 0; 143 | charsConverted = 0; 144 | wstr_length = SysStringLen(query_result.bstrVal); 145 | if (wstr_length == 0) 146 | nulls[Anum_percent_memory_usage] = true; 147 | else 148 | { 149 | dst = (char *)malloc(wstr_length + 10); 150 | memset(dst, 0x00, (wstr_length + 10)); 151 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 152 | long long val = strtoll(dst, NULL, 10); 153 | values[Anum_process_memory_bytes] = UInt64GetDatum(val); 154 | float4 memory_usage_per = (float4)(val / total_physical_memory) * 100; 155 | values[Anum_percent_memory_usage] = Float4GetDatum(memory_usage_per); 156 | free(dst); 157 | } 158 | VariantClear(&query_result); 159 | } 160 | 161 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 162 | 163 | /* release the current result object */ 164 | result->lpVtbl->Release(result); 165 | } 166 | 167 | /* release results set */ 168 | results->lpVtbl->Release(results); 169 | } 170 | else 171 | ereport(DEBUG1, (errmsg("[ReadCPUMemoryByProcess]: Failed to get query result"))); 172 | 173 | SysFreeString(query); 174 | } 175 | -------------------------------------------------------------------------------- /windows/cpu_usage_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * cpu_usage_info.c 3 | * System CPU usage information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | 16 | void ReadCPUUsageStatistics(Tuplestorestate *tupstore, TupleDesc tupdesc) 17 | { 18 | Datum values[Natts_cpu_usage_stats]; 19 | bool nulls[Natts_cpu_usage_stats]; 20 | 21 | memset(nulls, 0, sizeof(nulls)); 22 | 23 | // result code from COM calls from program 24 | HRESULT hres = 0; 25 | IEnumWbemClassObject *results = NULL; 26 | BSTR query = SysAllocString(L"SELECT * FROM Win32_PerfFormattedData_PerfOS_Processor"); 27 | 28 | // issue a WMI query 29 | results = execute_query(query); 30 | 31 | /* list the query results */ 32 | if (results != NULL) 33 | { 34 | IWbemClassObject *result = NULL; 35 | ULONG returnedCount = 0; 36 | 37 | // enumerate the retrieved objects 38 | while ((hres = results->lpVtbl->Next(results, WBEM_INFINITE, 1, &result, &returnedCount)) == S_OK) 39 | { 40 | VARIANT query_result; 41 | 42 | int wstr_length = 0; 43 | char *dst = NULL; 44 | size_t charsConverted = 0; 45 | 46 | hres = result->lpVtbl->Get(result, L"PercentIdleTime", 0, &query_result, 0, 0); 47 | if (FAILED(hres)) 48 | nulls[Anum_idle_mode] = true; 49 | else 50 | { 51 | wstr_length = 0; 52 | charsConverted = 0; 53 | wstr_length = SysStringLen(query_result.bstrVal); 54 | if (wstr_length == 0) 55 | nulls[Anum_idle_mode] = true; 56 | else 57 | { 58 | dst = (char *)malloc(wstr_length + 10); 59 | memset(dst, 0x00, (wstr_length + 10)); 60 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 61 | long long percent_time = strtoll(dst, NULL, 10); 62 | values[Anum_idle_mode] = Float4GetDatum((float)percent_time); 63 | free(dst); 64 | } 65 | VariantClear(&query_result); 66 | } 67 | 68 | hres = result->lpVtbl->Get(result, L"PercentInterruptTime", 0, &query_result, 0, 0); 69 | if (FAILED(hres)) 70 | nulls[Anum_percent_interrupt_time] = true; 71 | else 72 | { 73 | wstr_length = 0; 74 | charsConverted = 0; 75 | wstr_length = SysStringLen(query_result.bstrVal); 76 | if (wstr_length == 0) 77 | nulls[Anum_percent_interrupt_time] = true; 78 | else 79 | { 80 | dst = (char *)malloc(wstr_length + 10); 81 | memset(dst, 0x00, (wstr_length + 10)); 82 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 83 | long long percent_time = strtoll(dst, NULL, 10); 84 | values[Anum_percent_interrupt_time] = Float4GetDatum((float)percent_time); 85 | free(dst); 86 | } 87 | VariantClear(&query_result); 88 | } 89 | 90 | hres = result->lpVtbl->Get(result, L"PercentPrivilegedTime", 0, &query_result, 0, 0); 91 | if (FAILED(hres)) 92 | nulls[Anum_percent_privileged_time] = true; 93 | else 94 | { 95 | wstr_length = 0; 96 | charsConverted = 0; 97 | wstr_length = SysStringLen(query_result.bstrVal); 98 | if (wstr_length == 0) 99 | nulls[Anum_percent_privileged_time] = true; 100 | else 101 | { 102 | dst = (char *)malloc(wstr_length + 10); 103 | memset(dst, 0x00, (wstr_length + 10)); 104 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 105 | long long percent_time = strtoll(dst, NULL, 10); 106 | values[Anum_percent_privileged_time] = Float4GetDatum((float)percent_time); 107 | free(dst); 108 | } 109 | VariantClear(&query_result); 110 | } 111 | 112 | hres = result->lpVtbl->Get(result, L"PercentProcessorTime", 0, &query_result, 0, 0); 113 | if (FAILED(hres)) 114 | nulls[Anum_percent_processor_time] = true; 115 | else 116 | { 117 | wstr_length = 0; 118 | charsConverted = 0; 119 | wstr_length = SysStringLen(query_result.bstrVal); 120 | if (wstr_length == 0) 121 | nulls[Anum_percent_processor_time] = true; 122 | else 123 | { 124 | dst = (char *)malloc(wstr_length + 10); 125 | memset(dst, 0x00, (wstr_length + 10)); 126 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 127 | long long percent_time = strtoll(dst, NULL, 10); 128 | values[Anum_percent_processor_time] = Float4GetDatum((float)percent_time); 129 | free(dst); 130 | } 131 | VariantClear(&query_result); 132 | } 133 | 134 | hres = result->lpVtbl->Get(result, L"PercentUserTime", 0, &query_result, 0, 0); 135 | if (FAILED(hres)) 136 | nulls[Anum_percent_user_time] = true; 137 | else 138 | { 139 | wstr_length = 0; 140 | charsConverted = 0; 141 | wstr_length = SysStringLen(query_result.bstrVal); 142 | if (wstr_length == 0) 143 | nulls[Anum_percent_user_time] = true; 144 | else 145 | { 146 | dst = (char *)malloc(wstr_length + 10); 147 | memset(dst, 0x00, (wstr_length + 10)); 148 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 149 | long long percent_time = strtoll(dst, NULL, 10); 150 | values[Anum_percent_user_time] = Float4GetDatum((float)percent_time); 151 | free(dst); 152 | } 153 | VariantClear(&query_result); 154 | } 155 | 156 | nulls[Anum_usermode_normal_process] = true; 157 | nulls[Anum_usermode_niced_process] = true; 158 | nulls[Anum_kernelmode_process] = true; 159 | nulls[Anum_io_completion] = true; 160 | nulls[Anum_servicing_irq] = true; 161 | nulls[Anum_servicing_softirq] = true; 162 | 163 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 164 | 165 | /* release the current result object */ 166 | result->lpVtbl->Release(result); 167 | break; 168 | } 169 | 170 | /* release results set */ 171 | results->lpVtbl->Release(results); 172 | } 173 | else 174 | ereport(DEBUG1, (errmsg("[ReadCPUUsageStatistics]: Failed to get query result"))); 175 | 176 | SysFreeString(query); 177 | } 178 | -------------------------------------------------------------------------------- /windows/disk_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * disk_info.c 3 | * System disk information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | 16 | void ReadDiskInformation(Tuplestorestate *tupstore, TupleDesc tupdesc) 17 | { 18 | Datum values[Natts_disk_info]; 19 | bool nulls[Natts_disk_info]; 20 | 21 | memset(nulls, 0, sizeof(nulls)); 22 | 23 | // result code from COM calls from program 24 | HRESULT hres = 0; 25 | IEnumWbemClassObject *results = NULL; 26 | BSTR query = SysAllocString(L"SELECT * FROM Win32_Volume"); 27 | 28 | // issue a WMI query 29 | results = execute_query(query); 30 | 31 | /* list the query results */ 32 | if (results != NULL) 33 | { 34 | IWbemClassObject *result = NULL; 35 | ULONG returnedCount = 0; 36 | 37 | // enumerate the retrieved objects 38 | while ((hres = results->lpVtbl->Next(results, WBEM_INFINITE, 1, &result, &returnedCount)) == S_OK) 39 | { 40 | VARIANT query_result; 41 | uint64 total_space, free_space, used_space; 42 | 43 | int wstr_length = 0; 44 | char *dst = NULL; 45 | size_t charsConverted = 0; 46 | 47 | hres = result->lpVtbl->Get(result, L"DriveLetter", 0, &query_result, 0, 0); 48 | if (FAILED(hres)) 49 | nulls[Anum_disk_drive_letter] = true; 50 | else 51 | { 52 | wstr_length = 0; 53 | charsConverted = 0; 54 | wstr_length = SysStringLen(query_result.bstrVal); 55 | if (wstr_length == 0) 56 | nulls[Anum_disk_drive_letter] = true; 57 | else 58 | { 59 | dst = (char *)malloc(wstr_length + 10); 60 | memset(dst, 0x00, (wstr_length + 10)); 61 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 62 | values[Anum_disk_drive_letter] = CStringGetTextDatum(dst); 63 | free(dst); 64 | } 65 | VariantClear(&query_result); 66 | } 67 | 68 | hres = result->lpVtbl->Get(result, L"DriveType", 0, &query_result, 0, 0); 69 | if (FAILED(hres)) 70 | nulls[Anum_disk_drive_type] = true; 71 | else { 72 | values[Anum_disk_drive_type] = Int32GetDatum(query_result.intVal); 73 | VariantClear(&query_result); 74 | } 75 | 76 | hres = result->lpVtbl->Get(result, L"FileSystem", 0, &query_result, 0, 0); 77 | if (FAILED(hres)) 78 | nulls[Anum_disk_file_system] = true; 79 | else 80 | { 81 | wstr_length = 0; 82 | charsConverted = 0; 83 | wstr_length = SysStringLen(query_result.bstrVal); 84 | if (wstr_length == 0) 85 | nulls[Anum_disk_file_system] = true; 86 | else 87 | { 88 | dst = (char *)malloc(wstr_length + 10); 89 | memset(dst, 0x00, (wstr_length + 10)); 90 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 91 | values[Anum_disk_file_system] = CStringGetTextDatum(dst); 92 | free(dst); 93 | } 94 | VariantClear(&query_result); 95 | } 96 | 97 | hres = result->lpVtbl->Get(result, L"FreeSpace", 0, &query_result, 0, 0); 98 | if (FAILED(hres)) 99 | nulls[Anum_disk_free_space] = true; 100 | else 101 | { 102 | wstr_length = 0; 103 | charsConverted = 0; 104 | wstr_length = SysStringLen(query_result.bstrVal); 105 | if (wstr_length == 0) 106 | nulls[Anum_disk_free_space] = true; 107 | else 108 | { 109 | dst = (char *)malloc(wstr_length + 10); 110 | memset(dst, 0x00, (wstr_length + 10)); 111 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 112 | free_space = strtoll(dst, NULL, 10); 113 | values[Anum_disk_free_space] = UInt64GetDatum(free_space); 114 | free(dst); 115 | } 116 | VariantClear(&query_result); 117 | } 118 | 119 | hres = result->lpVtbl->Get(result, L"Capacity", 0, &query_result, 0, 0); 120 | if (FAILED(hres)) 121 | nulls[Anum_disk_total_space] = true; 122 | else 123 | { 124 | wstr_length = 0; 125 | charsConverted = 0; 126 | wstr_length = SysStringLen(query_result.bstrVal); 127 | if (wstr_length == 0) 128 | nulls[Anum_disk_total_space] = true; 129 | else 130 | { 131 | dst = (char *)malloc(wstr_length + 10); 132 | memset(dst, 0x00, (wstr_length + 10)); 133 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 134 | total_space = strtoll(dst, NULL, 10); 135 | values[Anum_disk_total_space] = UInt64GetDatum(total_space); 136 | free(dst); 137 | } 138 | VariantClear(&query_result); 139 | } 140 | 141 | used_space = (total_space - free_space); 142 | values[Anum_disk_used_space] = UInt64GetDatum(used_space); 143 | 144 | nulls[Anum_disk_mount_point] = true; 145 | nulls[Anum_disk_file_system_type] = true; 146 | nulls[Anum_disk_total_inodes] = true; 147 | nulls[Anum_disk_used_inodes] = true; 148 | nulls[Anum_disk_free_inodes] = true; 149 | 150 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 151 | 152 | /* release the current result object */ 153 | result->lpVtbl->Release(result); 154 | } 155 | 156 | /* release results set */ 157 | results->lpVtbl->Release(results); 158 | } 159 | else 160 | ereport(DEBUG1, (errmsg("[ReadDiskInformation]: Failed to get query result"))); 161 | 162 | SysFreeString(query); 163 | } 164 | -------------------------------------------------------------------------------- /windows/io_analysis.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * io_analysis.c 3 | * System IO analysis information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #define MAX_DRIVE_COUNT 32 18 | #define MAX_DEVICE_PATH 1024 19 | 20 | /* Function used to get IO statistics of block devices */ 21 | void ReadIOAnalysisInformation(Tuplestorestate *tupstore, TupleDesc tupdesc) 22 | { 23 | Datum values[Natts_io_analysis_info]; 24 | bool nulls[Natts_io_analysis_info]; 25 | DISK_PERFORMANCE diskPerformance; 26 | HANDLE hDevice = NULL; 27 | char szDevice[MAX_DEVICE_PATH]; 28 | char szDeviceDisplay[MAX_DEVICE_PATH]; 29 | int deviceId; 30 | int icount; 31 | DWORD ioctrlSize; 32 | DWORD dwSize; 33 | BOOL ret; 34 | 35 | memset(nulls, 0, sizeof(nulls)); 36 | memset(szDevice, 0, MAX_DEVICE_PATH); 37 | memset(szDeviceDisplay, 0, MAX_DEVICE_PATH); 38 | 39 | for (deviceId = 0; deviceId <= MAX_DRIVE_COUNT; ++deviceId) 40 | { 41 | snprintf(szDevice, MAX_DEVICE_PATH, "\\\\.\\PhysicalDrive%d", deviceId); 42 | 43 | hDevice = CreateFile(szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 44 | NULL, OPEN_EXISTING, 0, NULL); 45 | 46 | if (hDevice == INVALID_HANDLE_VALUE) 47 | continue; 48 | 49 | icount = 0; 50 | ioctrlSize = sizeof(diskPerformance); 51 | while (1) 52 | { 53 | icount += 1; 54 | ret = DeviceIoControl( 55 | hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, &diskPerformance, 56 | ioctrlSize, &dwSize, NULL); 57 | 58 | if (ret != 0) 59 | break; 60 | 61 | if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) 62 | { 63 | if (icount <= 1024) 64 | { 65 | ioctrlSize *= 2; 66 | continue; 67 | } 68 | } 69 | else if (GetLastError() == ERROR_INVALID_FUNCTION) 70 | { 71 | printf("DeviceIoControl->ERROR_INVALID_FUNCTION; ignore PhysicalDrive%d", deviceId); 72 | if (hDevice != NULL) 73 | CloseHandle(hDevice); 74 | return; 75 | } 76 | else if (GetLastError() == ERROR_NOT_SUPPORTED) 77 | { 78 | printf("DeviceIoControl -> ERROR_NOT_SUPPORTED; ignore PhysicalDrive%d", deviceId); 79 | if (hDevice != NULL) 80 | CloseHandle(hDevice); 81 | return; 82 | } 83 | 84 | if (hDevice != NULL) 85 | CloseHandle(hDevice); 86 | 87 | return; 88 | } 89 | 90 | snprintf(szDeviceDisplay, MAX_DEVICE_PATH, "PhysicalDrive%i", deviceId); 91 | 92 | values[Anum_device_name] = CStringGetTextDatum(szDeviceDisplay); 93 | values[Anum_total_read] = UInt64GetDatum((uint64)diskPerformance.ReadCount); 94 | values[Anum_total_write] = UInt64GetDatum((uint64)diskPerformance.WriteCount); 95 | values[Anum_read_bytes] = UInt64GetDatum((uint64)(diskPerformance.BytesRead.QuadPart)); 96 | values[Anum_write_bytes] = UInt64GetDatum((uint64)(diskPerformance.BytesWritten.QuadPart)); 97 | values[Anum_read_time_ms] = UInt64GetDatum((uint64)(diskPerformance.ReadTime.QuadPart) / 10000000); 98 | values[Anum_write_time_ms] = UInt64GetDatum((uint64)(diskPerformance.WriteTime.QuadPart) / 10000000); 99 | 100 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 101 | 102 | if (hDevice != NULL) 103 | CloseHandle(hDevice); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /windows/load_avg.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * load_avg.c 3 | * System load average information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | 16 | #pragma comment(lib, "Pdh.lib") 17 | 18 | /* logic will be same as linux */ 19 | #define SAMPLING_INTERVAL 5 20 | /* This has been calculated as 1/exp(5/60) , As 5 is sampling interval 5 second and 60 is for load avg of 1 minute ( 60 Seconds ) */ 21 | #define LOAD_AVG_1F 0.920044 22 | /* This has been calculated as 1/exp(5/300) , As 5 is sampling interval 5 second and for load avg of 5 minutes ( 300 Seconds ) */ 23 | #define LOAD_AVG_5F 0.983471 24 | /* This has been calculated as 1/exp(5/900) , As 5 is sampling interval 5 second and for load avg of 15 minutes ( 900 Seconds ) */ 25 | #define LOAD_AVG_15F 0.994459 26 | 27 | bool load_avg_initialized = false; 28 | double load_avg_1m = 0; 29 | double load_avg_5m = 0; 30 | double load_avg_10m = 0; 31 | double load_avg_15m = 0; 32 | 33 | VOID CALLBACK LoadAvgCallback(PVOID hCounter) 34 | { 35 | PDH_FMT_COUNTERVALUE displayValue; 36 | double currentLoad; 37 | PDH_STATUS err; 38 | 39 | err = PdhGetFormattedCounterValue( 40 | (PDH_HCOUNTER)hCounter, PDH_FMT_DOUBLE, 0, &displayValue); 41 | // Skip updating the load if we can't get the value successfully 42 | if (err != ERROR_SUCCESS) { 43 | return; 44 | } 45 | 46 | currentLoad = displayValue.doubleValue; 47 | 48 | load_avg_1m = load_avg_1m * LOAD_AVG_1F + currentLoad * (1.0 - LOAD_AVG_1F); 49 | load_avg_5m = load_avg_5m * LOAD_AVG_5F + currentLoad * (1.0 - LOAD_AVG_5F); 50 | load_avg_15m = load_avg_15m * LOAD_AVG_15F + currentLoad * (1.0 - LOAD_AVG_15F); 51 | } 52 | 53 | void initialize_load_avg_info() 54 | { 55 | WCHAR *szCounterPath = L"\\System\\Processor Queue Length"; 56 | PDH_STATUS s; 57 | BOOL ret; 58 | HQUERY hQuery; 59 | HCOUNTER hCounter; 60 | HANDLE event; 61 | HANDLE waitHandle; 62 | 63 | if ((PdhOpenQueryW(NULL, 0, &hQuery)) != ERROR_SUCCESS) 64 | { 65 | ereport(DEBUG1, (errmsg("[initialize_load_avg_info]: PdhOpenQueryW is failed"))); 66 | return; 67 | } 68 | 69 | s = PdhAddEnglishCounterW(hQuery, szCounterPath, 0, &hCounter); 70 | if (s != ERROR_SUCCESS) 71 | { 72 | ereport(DEBUG1, (errmsg("[initialize_load_avg_info]: PdhAddEnglishCounterW is failed"))); 73 | return; 74 | } 75 | 76 | event = CreateEventW(NULL, FALSE, FALSE, L"LoadUpdateEvent"); 77 | if (event == NULL) 78 | { 79 | ereport(DEBUG1, (errmsg("[initialize_load_avg_info]: CreateEventW is failed"))); 80 | return; 81 | } 82 | 83 | s = PdhCollectQueryDataEx(hQuery, SAMPLING_INTERVAL, event); 84 | if (s != ERROR_SUCCESS) 85 | { 86 | ereport(DEBUG1, (errmsg("[initialize_load_avg_info]: PdhCollectQueryDataEx is failed"))); 87 | return; 88 | } 89 | 90 | ret = RegisterWaitForSingleObject( 91 | &waitHandle, 92 | event, 93 | (WAITORTIMERCALLBACK)LoadAvgCallback, 94 | (PVOID) 95 | hCounter, 96 | INFINITE, 97 | WT_EXECUTEDEFAULT); 98 | 99 | if (ret == 0) 100 | { 101 | ereport(DEBUG1, (errmsg("[initialize_load_avg_info]: RegisterWaitForSingleObject is failed"))); 102 | return; 103 | } 104 | } 105 | 106 | void ReadLoadAvgInformations(Tuplestorestate *tupstore, TupleDesc tupdesc) 107 | { 108 | Datum values[Natts_load_avg_info]; 109 | bool nulls[Natts_load_avg_info]; 110 | 111 | memset(nulls, 0, sizeof(nulls)); 112 | 113 | /* InitialiZe the count to get the samples */ 114 | if (!load_avg_initialized) 115 | { 116 | ereport(DEBUG1, (errmsg("[ReadLoadAvgInformations]: Initializing counter for load average"))); 117 | initialize_load_avg_info(); 118 | load_avg_initialized = true; 119 | } 120 | else 121 | ereport(DEBUG1, (errmsg("[ReadLoadAvgInformations]: Counter already initializing for load average"))); 122 | 123 | values[Anum_load_avg_one_minute] = Float4GetDatum((float4)load_avg_1m); 124 | values[Anum_load_avg_five_minutes] = Float4GetDatum((float4)load_avg_5m); 125 | values[Anum_load_avg_ten_minutes] = Float4GetDatum((float4)load_avg_10m); 126 | values[Anum_load_avg_fifteen_minutes] = Float4GetDatum((float4)load_avg_15m); 127 | 128 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 129 | } 130 | -------------------------------------------------------------------------------- /windows/memory_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * memory_info.c 3 | * System memory information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | #include "postgres.h" 10 | #include "system_stats.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #pragma comment(lib, "psapi.lib") 18 | 19 | void ReadMemoryInformation(Tuplestorestate *tupstore, TupleDesc tupdesc) 20 | { 21 | Datum values[Natts_memory_info]; 22 | bool nulls[Natts_memory_info]; 23 | uint64 total_physical_memory = 0; 24 | uint64 avail_physical_memory = 0; 25 | uint64 memory_load_percentage = 0; 26 | uint64 total_page_file = 0; 27 | uint64 avail_page_file = 0; 28 | uint64 total_system_cache = 0; 29 | uint64 kernel_total = 0; 30 | uint64 kernel_paged = 0; 31 | uint64 kernel_non_paged = 0; 32 | MEMORYSTATUSEX statex; 33 | 34 | memset(nulls, 0, sizeof(nulls)); 35 | 36 | statex.dwLength = sizeof(statex); 37 | 38 | if (GlobalMemoryStatusEx(&statex) == 0) 39 | { 40 | LPVOID lpMsgBuf; 41 | DWORD dw = GetLastError(); 42 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 43 | NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL); 44 | ereport(DEBUG1, (errmsg("Error while getting memory information: %s", (char *)lpMsgBuf))); 45 | LocalFree(lpMsgBuf); 46 | return; 47 | } 48 | 49 | total_physical_memory = (uint64)statex.ullTotalPhys; 50 | avail_physical_memory = (uint64)statex.ullAvailPhys; 51 | total_page_file = (uint64)statex.ullTotalPageFile; 52 | avail_page_file = (uint64)statex.ullAvailPageFile; 53 | 54 | PERFORMANCE_INFORMATION per_statex; 55 | per_statex.cb = sizeof(per_statex); 56 | if (GetPerformanceInfo(&per_statex, per_statex.cb) == 0) 57 | { 58 | LPVOID lpMsgBuf; 59 | DWORD dw = GetLastError(); 60 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 61 | NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL); 62 | ereport(DEBUG1, (errmsg("Error while getting memory peformance information: %s", (char *)lpMsgBuf))); 63 | LocalFree(lpMsgBuf); 64 | } 65 | else 66 | { 67 | uint64 page_size = (uint64)per_statex.PageSize; 68 | total_system_cache = ((uint64)(per_statex.SystemCache)) * page_size; 69 | kernel_total = ((uint64)(per_statex.KernelTotal)) * page_size; 70 | kernel_paged = ((uint64)(per_statex.KernelPaged)) * page_size; 71 | kernel_non_paged = ((uint64)(per_statex.KernelNonpaged)) * page_size; 72 | } 73 | 74 | values[Anum_total_memory] = UInt64GetDatum(total_physical_memory); 75 | values[Anum_used_memory] = UInt64GetDatum((total_physical_memory - avail_physical_memory)); 76 | values[Anum_free_memory] = UInt64GetDatum(avail_physical_memory); 77 | values[Anum_total_cache_memory] = UInt64GetDatum(total_system_cache); 78 | values[Anum_kernel_total_memory] = UInt64GetDatum(kernel_total); 79 | values[Anum_kernel_paged_memory] = UInt64GetDatum(kernel_paged); 80 | values[Anum_kernel_nonpaged_memory] = UInt64GetDatum(kernel_non_paged); 81 | values[Anum_total_page_file] = UInt64GetDatum(total_page_file); 82 | values[Anum_avail_page_file] = UInt64GetDatum(avail_page_file); 83 | 84 | /* NULL the value which is not required for this platform */ 85 | nulls[Anum_swap_total_memory] = true; 86 | nulls[Anum_swap_used_memory] = true; 87 | nulls[Anum_swap_free_memory] = true; 88 | 89 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 90 | } 91 | -------------------------------------------------------------------------------- /windows/network_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * network_info.c 3 | * System network information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #pragma comment(lib, "iphlpapi.lib") 15 | #pragma comment(lib, "ws2_32.lib") 16 | 17 | #define IP_ADDR_SIZE 20 18 | 19 | typedef struct iprow 20 | { 21 | int indx; 22 | char addr[IP_ADDR_SIZE]; 23 | } IPROW; 24 | 25 | void ReadNetworkInformations(Tuplestorestate *tupstore, TupleDesc tupdesc) 26 | { 27 | Datum values[Natts_network_info]; 28 | bool nulls[Natts_network_info]; 29 | int bufsize = 0; 30 | int retval = 0; 31 | int allocate_buffer_cnt = 0; 32 | PMIB_IPADDRTABLE ip_addr_table; 33 | MIB_IFTABLE *if_table; 34 | IPROW *ip_rows; 35 | 36 | memset(nulls, 0, sizeof(nulls)); 37 | 38 | // Populate the address table data-structure 39 | ip_addr_table = (MIB_IPADDRTABLE *)malloc(sizeof(MIB_IPADDRTABLE)); 40 | if (ip_addr_table == NULL) 41 | { 42 | ereport(DEBUG1, (errmsg("[ReadNetworkInformations]: Failed to allocate the memory"))); 43 | return; 44 | } 45 | 46 | /* Make an initial call to GetIpAddrTable to get the necessary size into the bufsize variable */ 47 | if (GetIpAddrTable(ip_addr_table, (PULONG)&bufsize, 0) == ERROR_INSUFFICIENT_BUFFER) 48 | { 49 | free(ip_addr_table); 50 | ip_addr_table = NULL; 51 | ip_addr_table = (MIB_IPADDRTABLE *)malloc(bufsize); 52 | if (ip_addr_table == NULL) 53 | { 54 | ereport(DEBUG1, (errmsg("[ReadNetworkInformations]: Failed to allocate the memory"))); 55 | return; 56 | } 57 | } 58 | 59 | /* Make a second call to GetIpAddrTable to get the actual data */ 60 | if ((retval = GetIpAddrTable(ip_addr_table, (PULONG)&bufsize, 0)) != NO_ERROR) 61 | { 62 | ereport(DEBUG1, (errmsg("[ReadNetworkInformations]: GetIpAddrTable: Failed to get information"))); 63 | free(ip_addr_table); 64 | return; 65 | } 66 | 67 | /* First find the buffer size for allocation */ 68 | for (int iter = 0; iter < (int)ip_addr_table->dwNumEntries; iter++) 69 | { 70 | if ((ip_addr_table->table[iter].wType & MIB_IPADDR_PRIMARY) || (ip_addr_table->table[iter].wType & MIB_IPADDR_DYNAMIC)) 71 | allocate_buffer_cnt++; 72 | } 73 | 74 | if (allocate_buffer_cnt != 0) 75 | { 76 | ip_rows = (IPROW *)malloc(allocate_buffer_cnt * sizeof(IPROW)); 77 | if (ip_rows == NULL) 78 | { 79 | ereport(DEBUG1, (errmsg("[ReadNetworkInformations]: Failed to allocate the memory"))); 80 | return; 81 | } 82 | 83 | memset(ip_rows, 0x00, allocate_buffer_cnt * sizeof(IPROW)); 84 | } 85 | else 86 | { 87 | ereport(DEBUG1, (errmsg("[ReadNetworkInformations]: No valid interface available"))); 88 | return; 89 | } 90 | 91 | for (int iter = 0; iter < (int)ip_addr_table->dwNumEntries; iter++) 92 | { 93 | if ((ip_addr_table->table[iter].wType & MIB_IPADDR_PRIMARY) || (ip_addr_table->table[iter].wType & MIB_IPADDR_DYNAMIC)) 94 | { 95 | int index = sizeof(IPROW) * iter; 96 | int ip_index = index + sizeof(int); 97 | IN_ADDR IPAddr; 98 | 99 | int val = ip_addr_table->table[iter].dwIndex; 100 | IPAddr.S_un.S_addr = (u_long)ip_addr_table->table[iter].dwAddr; 101 | char *ip_val = inet_ntoa(IPAddr); 102 | memcpy((ip_rows + index), (int *)&val, sizeof(int)); 103 | memcpy((ip_rows + ip_index), (char *)ip_val, IP_ADDR_SIZE); 104 | } 105 | } 106 | 107 | free(ip_addr_table); 108 | ip_addr_table = NULL; 109 | 110 | /* Populate the interface stat table data-structure */ 111 | if_table = (MIB_IFTABLE *)malloc(sizeof(MIB_IFTABLE)); 112 | if (if_table == NULL) 113 | { 114 | ereport(DEBUG1, (errmsg("[ReadNetworkInformations]: Failed to allocate the memory"))); 115 | free(ip_rows); 116 | return; 117 | } 118 | 119 | /* Make an initial call to GetIfTable to get the necessary size into bufsize */ 120 | if (GetIfTable(if_table, (PULONG)&bufsize, FALSE) == ERROR_INSUFFICIENT_BUFFER) 121 | { 122 | free(if_table); 123 | if_table = (MIB_IFTABLE *)malloc(bufsize); 124 | if (if_table == NULL) 125 | { 126 | ereport(DEBUG1, (errmsg("[ReadNetworkInformations]: Failed to allocate the memory"))); 127 | free(ip_rows); 128 | return; 129 | } 130 | } 131 | 132 | /* Make a second call to GetIfTable to get the actual data */ 133 | if ((retval = GetIfTable(if_table, (PULONG)&bufsize, FALSE)) != NO_ERROR) 134 | { 135 | ereport(DEBUG1, (errmsg("[ReadNetworkInformations]: GetIfTable: Failed to get information"))); 136 | free(if_table); 137 | free(ip_rows); 138 | return; 139 | } 140 | 141 | for (int o_index = 0; o_index < (int)allocate_buffer_cnt; o_index++) 142 | { 143 | for (int i_index = 0; i_index < (int)if_table->dwNumEntries; i_index++) 144 | { 145 | MIB_IFROW *if_row = (MIB_IFROW *)& if_table->table[i_index]; 146 | int index = sizeof(IPROW) * o_index; 147 | int ip_index = index + sizeof(int); 148 | 149 | int val = *(int*)(ip_rows + index); 150 | 151 | if (val == if_row->dwIndex) 152 | { 153 | if (if_row->dwType == IF_TYPE_ETHERNET_CSMACD || 154 | if_row->dwType == IF_TYPE_IEEE80211 || 155 | if_row->dwType == IF_TYPE_SOFTWARE_LOOPBACK || 156 | if_row->dwType == IF_TYPE_IEEE1394) 157 | { 158 | bool IsLoopbackType = false; 159 | if (if_row->dwType == IF_TYPE_SOFTWARE_LOOPBACK) 160 | IsLoopbackType = true; 161 | 162 | /* if the interface is not valid */ 163 | if (IsLoopbackType == false && 164 | (if_row->dwOperStatus != IF_OPER_STATUS_OPERATIONAL || 165 | if_row->dwPhysAddrLen == 0)) 166 | continue; 167 | 168 | int wstr_length = 0; 169 | char *dst = NULL; 170 | size_t charsConverted = 0; 171 | 172 | wstr_length = (int)wcslen(if_row->wszName); 173 | if (wstr_length == 0) 174 | nulls[Anum_net_interface_name] = true; 175 | else 176 | { 177 | dst = (char *)malloc(wstr_length + 10); 178 | memset(dst, 0x00, (wstr_length + 10)); 179 | wcstombs_s(&charsConverted, dst, wstr_length + 10, if_row->wszName, wstr_length); 180 | values[Anum_net_interface_name] = CStringGetTextDatum(dst); 181 | free(dst); 182 | } 183 | 184 | values[Anum_net_ipv4_address] = CStringGetTextDatum((char *)(ip_rows + ip_index)); 185 | values[Anum_net_tx_packets] = UInt64GetDatum((uint64)(if_row->dwOutUcastPkts + if_row->dwOutNUcastPkts)); 186 | values[Anum_net_rx_packets] = UInt64GetDatum((uint64)(if_row->dwInUcastPkts + if_row->dwInNUcastPkts)); 187 | values[Anum_net_tx_bytes] = UInt64GetDatum((uint64)if_row->dwOutOctets); 188 | values[Anum_net_rx_bytes] = UInt64GetDatum((uint64)if_row->dwInOctets); 189 | values[Anum_net_tx_dropped] = UInt64GetDatum((uint64)if_row->dwOutDiscards); 190 | values[Anum_net_rx_dropped] = UInt64GetDatum((uint64)if_row->dwInDiscards); 191 | values[Anum_net_tx_errors] = UInt64GetDatum((uint64)if_row->dwOutErrors); 192 | values[Anum_net_rx_errors] = UInt64GetDatum((uint64)if_row->dwInErrors); 193 | values[Anum_net_speed_mbps] = Int32GetDatum((int)(if_row->dwSpeed / 1000000)); 194 | 195 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 196 | } 197 | } 198 | } 199 | } 200 | 201 | if (if_table != NULL) 202 | { 203 | free(if_table); 204 | if_table = NULL; 205 | } 206 | 207 | if (ip_rows != NULL) 208 | { 209 | free(ip_rows); 210 | ip_rows = NULL; 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /windows/os_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * os_info.c 3 | * Operating system information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #pragma comment(lib, "psapi.lib") 18 | 19 | void ReadOSInformations(Tuplestorestate *tupstore, TupleDesc tupdesc) 20 | { 21 | Datum values[Natts_os_info]; 22 | bool nulls[Natts_os_info]; 23 | int handle_count = 0; 24 | int process_count = 0; 25 | int thread_count = 0; 26 | 27 | memset(nulls, 0, sizeof(nulls)); 28 | 29 | PERFORMANCE_INFORMATION per_statex; 30 | per_statex.cb = sizeof(per_statex); 31 | if (GetPerformanceInfo(&per_statex, per_statex.cb) == 0) 32 | { 33 | LPVOID lpMsgBuf; 34 | DWORD dw = GetLastError(); 35 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 36 | NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL); 37 | ereport(DEBUG1, (errmsg("Error while getting memory peformance information: %s", (char *)lpMsgBuf))); 38 | LocalFree(lpMsgBuf); 39 | } 40 | else 41 | { 42 | handle_count = (int)(per_statex.HandleCount); 43 | process_count = (int)(per_statex.ProcessCount); 44 | thread_count = (int)(per_statex.ThreadCount); 45 | } 46 | 47 | // result code from COM calls from program 48 | HRESULT hres = 0; 49 | IEnumWbemClassObject *results = NULL; 50 | BSTR query = SysAllocString(L"SELECT * FROM Win32_Operatingsystem"); 51 | 52 | // issue a WMI query 53 | results = execute_query(query); 54 | 55 | /* list the query results */ 56 | if (results != NULL) 57 | { 58 | IWbemClassObject *result = NULL; 59 | ULONG returnedCount = 0; 60 | 61 | // enumerate the retrieved objects 62 | while ((hres = results->lpVtbl->Next(results, WBEM_INFINITE, 1, &result, &returnedCount)) == S_OK) 63 | { 64 | VARIANT query_result; 65 | int wstr_length = 0; 66 | char *dst = NULL; 67 | size_t charsConverted = 0; 68 | 69 | /* Get the value from query output */ 70 | hres = result->lpVtbl->Get(result, L"Caption", 0, &query_result, 0, 0); 71 | if (FAILED(hres)) 72 | nulls[Anum_os_name] = true; 73 | else 74 | { 75 | wstr_length = SysStringLen(query_result.bstrVal); 76 | if (wstr_length == 0) 77 | nulls[Anum_os_name] = true; 78 | else 79 | { 80 | dst = (char *)malloc(wstr_length + 10); 81 | memset(dst, 0x00, (wstr_length + 10)); 82 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 83 | values[Anum_os_name] = CStringGetTextDatum(dst); 84 | free(dst); 85 | } 86 | VariantClear(&query_result); 87 | } 88 | 89 | hres = result->lpVtbl->Get(result, L"Version", 0, &query_result, 0, 0); 90 | if (FAILED(hres)) 91 | nulls[Anum_os_version] = true; 92 | else 93 | { 94 | wstr_length = 0; 95 | charsConverted = 0; 96 | wstr_length = SysStringLen(query_result.bstrVal); 97 | if (wstr_length == 0) 98 | nulls[Anum_os_version] = true; 99 | else 100 | { 101 | dst = (char *)malloc(wstr_length + 10); 102 | memset(dst, 0x00, (wstr_length + 10)); 103 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 104 | values[Anum_os_version] = CStringGetTextDatum(dst); 105 | free(dst); 106 | } 107 | VariantClear(&query_result); 108 | } 109 | 110 | hres = result->lpVtbl->Get(result, L"CSName", 0, &query_result, 0, 0); 111 | if (FAILED(hres)) 112 | nulls[Anum_host_name] = true; 113 | else 114 | { 115 | wstr_length = 0; 116 | charsConverted = 0; 117 | wstr_length = SysStringLen(query_result.bstrVal); 118 | if (wstr_length == 0) 119 | nulls[Anum_host_name] = true; 120 | else 121 | { 122 | dst = (char *)malloc(wstr_length + 10); 123 | memset(dst, 0x00, (wstr_length + 10)); 124 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 125 | values[Anum_host_name] = CStringGetTextDatum(dst); 126 | free(dst); 127 | } 128 | VariantClear(&query_result); 129 | } 130 | 131 | hres = result->lpVtbl->Get(result, L"OSArchitecture", 0, &query_result, 0, 0); 132 | if (FAILED(hres)) 133 | nulls[Anum_os_architecture] = true; 134 | else 135 | { 136 | wstr_length = 0; 137 | charsConverted = 0; 138 | wstr_length = SysStringLen(query_result.bstrVal); 139 | if (wstr_length == 0) 140 | nulls[Anum_os_architecture] = true; 141 | else 142 | { 143 | dst = (char *)malloc(wstr_length + 10); 144 | memset(dst, 0x00, (wstr_length + 10)); 145 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 146 | values[Anum_os_architecture] = CStringGetTextDatum(dst); 147 | free(dst); 148 | } 149 | VariantClear(&query_result); 150 | } 151 | 152 | hres = result->lpVtbl->Get(result, L"LastBootUpTime", 0, &query_result, 0, 0); 153 | if (FAILED(hres)) 154 | nulls[Anum_os_boot_time] = true; 155 | else 156 | { 157 | wstr_length = 0; 158 | charsConverted = 0; 159 | wstr_length = SysStringLen(query_result.bstrVal); 160 | if (wstr_length == 0) 161 | nulls[Anum_os_boot_time] = true; 162 | else 163 | { 164 | dst = (char *)malloc(wstr_length + 10); 165 | memset(dst, 0x00, (wstr_length + 10)); 166 | wcstombs_s(&charsConverted, dst, wstr_length + 10, query_result.bstrVal, wstr_length); 167 | values[Anum_os_boot_time] = CStringGetTextDatum(dst); 168 | free(dst); 169 | } 170 | VariantClear(&query_result); 171 | } 172 | 173 | values[Anum_os_handle_count] = handle_count; 174 | values[Anum_os_process_count] = process_count; 175 | values[Anum_os_thread_count] = thread_count; 176 | 177 | /* set the NULL value for column which is not required by this platform */ 178 | nulls[Anum_domain_name] = true; 179 | nulls[Anum_os_up_since_seconds] = true; 180 | 181 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 182 | 183 | /* release the current result object */ 184 | result->lpVtbl->Release(result); 185 | } 186 | 187 | /* release results set */ 188 | results->lpVtbl->Release(results); 189 | } 190 | else 191 | ereport(DEBUG1, (errmsg("[ReadOSInformations]: Failed to get query result"))); 192 | 193 | SysFreeString(query); 194 | } 195 | -------------------------------------------------------------------------------- /windows/process_info.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * process_info.c 3 | * System process information 4 | * 5 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 6 | * 7 | *------------------------------------------------------------------------ 8 | */ 9 | 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | 16 | void ReadProcessInformations(Tuplestorestate *tupstore, TupleDesc tupdesc) 17 | { 18 | Datum values[Natts_process_info]; 19 | bool nulls[Natts_process_info]; 20 | 21 | memset(nulls, 0, sizeof(nulls)); 22 | 23 | // result code from COM calls from program 24 | HRESULT hres = 0; 25 | IEnumWbemClassObject *results = NULL; 26 | BSTR query = SysAllocString(L"SELECT * FROM Win32_Process"); 27 | 28 | // issue a WMI query 29 | results = execute_query(query); 30 | 31 | /* list the query results */ 32 | if (results != NULL) 33 | { 34 | IWbemClassObject *result = NULL; 35 | ULONG returnedCount = 0; 36 | int no_of_total_processes = 0; 37 | int no_of_running_processes = 0; 38 | int no_of_stopped_processes = 0; 39 | 40 | // enumerate the retrieved objects 41 | while ((hres = results->lpVtbl->Next(results, WBEM_INFINITE, 1, &result, &returnedCount)) == S_OK) 42 | { 43 | VARIANT query_result; 44 | int pid = 0; 45 | 46 | /* Get the value from query output */ 47 | hres = result->lpVtbl->Get(result, L"ProcessId", 0, &query_result, 0, 0); 48 | if (FAILED(hres)) 49 | continue; 50 | else 51 | { 52 | pid = query_result.intVal; 53 | 54 | no_of_total_processes++; 55 | 56 | if (is_process_running(pid)) 57 | no_of_running_processes++; 58 | else 59 | no_of_stopped_processes++; 60 | 61 | VariantClear(&query_result); 62 | } 63 | 64 | /* release the current result object */ 65 | result->lpVtbl->Release(result); 66 | } 67 | 68 | values[Anum_no_of_total_processes] = Int32GetDatum(no_of_total_processes); 69 | values[Anum_no_of_running_processes] = Int32GetDatum(no_of_running_processes); 70 | values[Anum_no_of_stopped_processes] = Int32GetDatum(no_of_stopped_processes); 71 | 72 | /* NULL the platform independent value */ 73 | nulls[Anum_no_of_sleeping_processes] = true; 74 | nulls[Anum_no_of_zombie_processes] = true; 75 | 76 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 77 | 78 | /* release results set */ 79 | results->lpVtbl->Release(results); 80 | } 81 | else 82 | ereport(DEBUG1, (errmsg("[ReadProcessInformations]: Failed to get query result"))); 83 | 84 | SysFreeString(query); 85 | } 86 | -------------------------------------------------------------------------------- /windows/system_stats_utils.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------ 2 | * system_stats_utils.c 3 | * Defined required utility functions to fetch 4 | * system statistics information 5 | * 6 | * Copyright (c) 2020, EnterpriseDB Corporation. All Rights Reserved. 7 | * 8 | *------------------------------------------------------------------------ 9 | */ 10 | #include "postgres.h" 11 | #include "system_stats.h" 12 | 13 | #include 14 | #include 15 | 16 | #define THREAD_WAITING_STATE 5 17 | #define THREAD_WAIT_REASON 5 18 | 19 | // Initialize COM interface pointers 20 | IWbemLocator *locator = NULL; 21 | IWbemServices *services = NULL; 22 | 23 | int is_process_running(int pid); 24 | 25 | /* Check if all the threads of the process is running or not */ 26 | int is_process_running(int pid) 27 | { 28 | // result code from COM calls from program 29 | HRESULT hres = 0; 30 | int ret_val = 0; 31 | char ptr[512] = { 0 }; 32 | wchar_t w_query[512]; 33 | size_t outSize; 34 | char pid_str[20] = { 0 }; 35 | snprintf(pid_str, sizeof(pid_str), "%d", pid); 36 | snprintf(ptr, sizeof(ptr), "SELECT ThreadState, ThreadWaitReason FROM Win32_Thread WHERE ProcessHandle = %s", pid_str); 37 | mbstowcs_s(&outSize, w_query, sizeof(ptr), ptr, sizeof(ptr)); 38 | 39 | IEnumWbemClassObject *results = NULL; 40 | BSTR query = SysAllocString(w_query); 41 | 42 | // issue a WMI query 43 | results = execute_query(query); 44 | 45 | /* list the query results */ 46 | if (results != NULL) 47 | { 48 | IWbemClassObject *result = NULL; 49 | ULONG returnedCount = 0; 50 | 51 | // enumerate the retrieved objects 52 | while ((hres = results->lpVtbl->Next(results, WBEM_INFINITE, 1, &result, &returnedCount)) == S_OK) 53 | { 54 | VARIANT query_result; 55 | int wait_state = 0; 56 | int wait_reason = 0; 57 | 58 | hres = result->lpVtbl->Get(result, L"ThreadState", 0, &query_result, 0, 0); 59 | if (FAILED(hres)) 60 | { 61 | elog(DEBUG1, "Failed to get ThreadState"); 62 | ret_val = 0; 63 | } 64 | else 65 | { 66 | wait_state = query_result.intVal; 67 | hres = result->lpVtbl->Get(result, L"ThreadWaitReason", 0, &query_result, 0, 0); 68 | if (FAILED(hres)) 69 | { 70 | elog(DEBUG1, "Failed to get ThreadWaitReason"); 71 | ret_val = 0; 72 | } 73 | else 74 | { 75 | wait_reason = query_result.intVal; 76 | if (wait_state != THREAD_WAITING_STATE || 77 | wait_reason != THREAD_WAIT_REASON) 78 | { 79 | ret_val = 1; 80 | break; 81 | } 82 | VariantClear(&query_result); 83 | } 84 | } 85 | 86 | /* release the current result object */ 87 | result->lpVtbl->Release(result); 88 | } 89 | 90 | /* release results set */ 91 | results->lpVtbl->Release(results); 92 | } 93 | else 94 | ereport(DEBUG1, (errmsg("[is_process_running]: Failed to get query result"))); 95 | 96 | SysFreeString(query); 97 | 98 | return ret_val; 99 | } 100 | 101 | void initialize_wmi_connection() 102 | { 103 | // result code from COM calls from program 104 | HRESULT hres = 0; 105 | 106 | BSTR resource = SysAllocString(L"ROOT\\CIMV2"); 107 | 108 | // initialize COM 109 | hres = CoInitializeEx(0, COINIT_MULTITHREADED); 110 | if (FAILED(hres)) 111 | { 112 | ereport(DEBUG1, (errmsg("[initialize_wmi_connection]: Failed to initialize COM library"))); 113 | return; 114 | } 115 | 116 | hres = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); 117 | if (FAILED(hres)) 118 | { 119 | ereport(DEBUG1, (errmsg("[initialize_wmi_connection]: Failed to initialize the security"))); 120 | CoUninitialize(); 121 | SysFreeString(resource); 122 | return; 123 | } 124 | 125 | /* Obtain the initial locator to Windows Management on a particular host computer */ 126 | hres = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, &IID_IWbemLocator, (LPVOID *)&locator); 127 | if (FAILED(hres)) 128 | { 129 | ereport(DEBUG1, (errmsg("[initialize_wmi_connection]: Failed to create IWbemLocator object"))); 130 | CoUninitialize(); 131 | SysFreeString(resource); 132 | return; 133 | } 134 | 135 | /* Connect to the root\cimv2 namespace with the current user and obtain pointer services to make IWbemServices calls */ 136 | hres = locator->lpVtbl->ConnectServer(locator, resource, NULL, NULL, NULL, 0, NULL, NULL, &services); 137 | if (FAILED(hres)) 138 | { 139 | ereport(DEBUG1, (errmsg("[initialize_wmi_connection]: Failed to create IWbemLocator object"))); 140 | locator->lpVtbl->Release(locator); 141 | CoUninitialize(); 142 | SysFreeString(resource); 143 | return; 144 | } 145 | 146 | ereport(DEBUG1, (errmsg("[initialize_wmi_connection]: Successfully initialized the service"))); 147 | 148 | SysFreeString(resource); 149 | 150 | execute_init_query(); 151 | } 152 | 153 | void uninitialize_wmi_connection() 154 | { 155 | services->lpVtbl->Release(services); 156 | locator->lpVtbl->Release(locator); 157 | CoUninitialize(); 158 | } 159 | 160 | /* Execute the query initially which took some time during execution 161 | so when user fire query, results will be given instantly */ 162 | void execute_init_query() 163 | { 164 | IEnumWbemClassObject *results = NULL; 165 | 166 | // result code from COM calls from program 167 | HRESULT hres = 0; 168 | BSTR language = SysAllocString(L"WQL"); 169 | 170 | if (services != NULL) 171 | { 172 | BSTR query = SysAllocString(L"SELECT * FROM Win32_PerfFormattedData_PerfProc_Process"); 173 | 174 | // issue a WMI query 175 | hres = services->lpVtbl->ExecQuery(services, language, query, WBEM_FLAG_BIDIRECTIONAL, NULL, &results); 176 | if (FAILED(hres)) 177 | ereport(DEBUG1, (errmsg("Failed to execute WQL query"))); 178 | 179 | /* Ignore the result as we are not intersted in */ 180 | if (results != NULL) 181 | results->lpVtbl->Release(results); 182 | 183 | SysFreeString(query); 184 | } 185 | 186 | SysFreeString(language); 187 | } 188 | 189 | IEnumWbemClassObject* execute_query(BSTR query) 190 | { 191 | IEnumWbemClassObject *results = NULL; 192 | 193 | // result code from COM calls from program 194 | HRESULT hres = 0; 195 | BSTR language = SysAllocString(L"WQL"); 196 | 197 | if (services != NULL) 198 | { 199 | // issue a WMI query 200 | hres = services->lpVtbl->ExecQuery(services, language, query, WBEM_FLAG_BIDIRECTIONAL, NULL, &results); 201 | if (FAILED(hres)) 202 | ereport(DEBUG1, (errmsg("Failed to execute WQL query"))); 203 | } 204 | else 205 | { 206 | /* Try to initialize it again and try one more time to execuet the query. 207 | * It may possible that during first initliaze, resoufce may busy so try again */ 208 | initialize_wmi_connection(); 209 | if (services != NULL) 210 | { 211 | // issue a WMI query 212 | hres = services->lpVtbl->ExecQuery(services, language, query, WBEM_FLAG_BIDIRECTIONAL, NULL, &results); 213 | if (FAILED(hres)) 214 | ereport(DEBUG1, (errmsg("Failed to execute WQL query"))); 215 | } 216 | } 217 | 218 | SysFreeString(language); 219 | 220 | return results; 221 | } 222 | --------------------------------------------------------------------------------