1570af302Sopenharmony_ci/* 2570af302Sopenharmony_ci * Copyright (C) 2022 Huawei Device Co., Ltd. 3570af302Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4570af302Sopenharmony_ci * you may not use this file except in compliance with the License. 5570af302Sopenharmony_ci * You may obtain a copy of the License at 6570af302Sopenharmony_ci * 7570af302Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8570af302Sopenharmony_ci * 9570af302Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10570af302Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11570af302Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12570af302Sopenharmony_ci * See the License for the specific language governing permissions and 13570af302Sopenharmony_ci * limitations under the License. 14570af302Sopenharmony_ci */ 15570af302Sopenharmony_ci 16570af302Sopenharmony_ci#ifndef TEST_MALLOC_STATS_H 17570af302Sopenharmony_ci#define TEST_MALLOC_STATS_H 18570af302Sopenharmony_ci 19570af302Sopenharmony_ci#define _GNU_SOURCE 20570af302Sopenharmony_ci 21570af302Sopenharmony_ci#include <pthread.h> 22570af302Sopenharmony_ci#include <malloc.h> 23570af302Sopenharmony_ci#include <unistd.h> 24570af302Sopenharmony_ci#include <sys/syscall.h> 25570af302Sopenharmony_ci#include <string.h> 26570af302Sopenharmony_ci#include <ctype.h> 27570af302Sopenharmony_ci#include <stdlib.h> 28570af302Sopenharmony_ci#include "test-malloc-stats-common.h" 29570af302Sopenharmony_ci#include "test.h" 30570af302Sopenharmony_ci 31570af302Sopenharmony_ci#define MAX_TID_LEN 32 32570af302Sopenharmony_ci#define STATS_BUFFER_SIZE 4096 33570af302Sopenharmony_ci 34570af302Sopenharmony_citypedef struct { 35570af302Sopenharmony_ci char stats_before_allocations[STATS_BUFFER_SIZE]; 36570af302Sopenharmony_ci char stats_after_allocations[STATS_BUFFER_SIZE]; 37570af302Sopenharmony_ci char stats_after_free[STATS_BUFFER_SIZE]; 38570af302Sopenharmony_ci char threads[SIZES_COUNT][MAX_TID_LEN + 1]; 39570af302Sopenharmony_ci} test_results_t; 40570af302Sopenharmony_ci 41570af302Sopenharmony_cistatic void stderr_stats_cb(void); 42570af302Sopenharmony_ci 43570af302Sopenharmony_cistatic int populate_thread_stats(const char *output, const char *thread_id, malloc_thread_stats_t *stats); 44570af302Sopenharmony_ci 45570af302Sopenharmony_cistatic int populate_total_free_heap_space(const char *output, long long *total_free_heap_space); 46570af302Sopenharmony_ci 47570af302Sopenharmony_cistatic int is_thread_in_output(const char *output, const char *thread_id); 48570af302Sopenharmony_ci 49570af302Sopenharmony_cistatic void print_to_file(void *fp, const char *s) 50570af302Sopenharmony_ci{ 51570af302Sopenharmony_ci fputs(s, fp); 52570af302Sopenharmony_ci} 53570af302Sopenharmony_ci 54570af302Sopenharmony_ciint stats_to_buffer(char *buffer) 55570af302Sopenharmony_ci{ 56570af302Sopenharmony_ci fflush(stderr); 57570af302Sopenharmony_ci int err_pipe[2]; 58570af302Sopenharmony_ci int saved_stderr = dup(STDERR_FILENO); 59570af302Sopenharmony_ci if (pipe(err_pipe) != 0) { 60570af302Sopenharmony_ci perror("Can't create pipe"); 61570af302Sopenharmony_ci return 0; 62570af302Sopenharmony_ci } 63570af302Sopenharmony_ci dup2(err_pipe[1], STDERR_FILENO); 64570af302Sopenharmony_ci close(err_pipe[1]); 65570af302Sopenharmony_ci stderr_stats_cb(); 66570af302Sopenharmony_ci fflush(stderr); 67570af302Sopenharmony_ci read(err_pipe[0], buffer, STATS_BUFFER_SIZE); 68570af302Sopenharmony_ci dup2(saved_stderr, STDERR_FILENO); 69570af302Sopenharmony_ci return 1; 70570af302Sopenharmony_ci} 71570af302Sopenharmony_ci 72570af302Sopenharmony_cistatic test_results_t get_main_thread_test_results(void) 73570af302Sopenharmony_ci{ 74570af302Sopenharmony_ci test_results_t test_results = {{0}, 75570af302Sopenharmony_ci {0}, 76570af302Sopenharmony_ci {0}, 77570af302Sopenharmony_ci {{0}}}; 78570af302Sopenharmony_ci 79570af302Sopenharmony_ci stats_to_buffer(test_results.stats_before_allocations); 80570af302Sopenharmony_ci 81570af302Sopenharmony_ci snprintf(test_results.threads[0], MAX_TID_LEN, "%d", (pid_t) syscall(__NR_gettid)); 82570af302Sopenharmony_ci 83570af302Sopenharmony_ci void *ptrs[SIZES_COUNT] = {0}; 84570af302Sopenharmony_ci for (size_t i = 0; i < SIZES_COUNT; i++) { 85570af302Sopenharmony_ci ptrs[i] = malloc(sizes[i]); 86570af302Sopenharmony_ci } 87570af302Sopenharmony_ci stats_to_buffer(test_results.stats_after_allocations); 88570af302Sopenharmony_ci for (size_t i = 0; i < SIZES_COUNT; i++) { 89570af302Sopenharmony_ci free(ptrs[i]); 90570af302Sopenharmony_ci } 91570af302Sopenharmony_ci stats_to_buffer(test_results.stats_after_free); 92570af302Sopenharmony_ci return test_results; 93570af302Sopenharmony_ci} 94570af302Sopenharmony_ci 95570af302Sopenharmony_cistatic test_results_t get_different_threads_test_results(void) 96570af302Sopenharmony_ci{ 97570af302Sopenharmony_ci test_results_t test_results = {{0}, 98570af302Sopenharmony_ci {0}, 99570af302Sopenharmony_ci {0}, 100570af302Sopenharmony_ci {{0}}}; 101570af302Sopenharmony_ci 102570af302Sopenharmony_ci stats_to_buffer(test_results.stats_before_allocations); 103570af302Sopenharmony_ci pthread_barrier_t alloc_barrier, free_barrier; 104570af302Sopenharmony_ci if (pthread_barrier_init(&alloc_barrier, NULL, SIZES_COUNT + 1)) { 105570af302Sopenharmony_ci return test_results; 106570af302Sopenharmony_ci } 107570af302Sopenharmony_ci if (pthread_barrier_init(&free_barrier, NULL, SIZES_COUNT + 1)) { 108570af302Sopenharmony_ci return test_results; 109570af302Sopenharmony_ci } 110570af302Sopenharmony_ci 111570af302Sopenharmony_ci thread_data_t thread_data[SIZES_COUNT]; 112570af302Sopenharmony_ci for (size_t i = 0; i < SIZES_COUNT; i++) { 113570af302Sopenharmony_ci thread_data[i] = (thread_data_t) {sizes[i], &alloc_barrier, &free_barrier, 0}; 114570af302Sopenharmony_ci } 115570af302Sopenharmony_ci pthread_t threads[SIZES_COUNT]; 116570af302Sopenharmony_ci for (size_t i = 0; i < SIZES_COUNT; i++) { 117570af302Sopenharmony_ci pthread_create(&threads[i], NULL, allocate_wait_free, &thread_data[i]); 118570af302Sopenharmony_ci } 119570af302Sopenharmony_ci pthread_barrier_wait(&alloc_barrier); 120570af302Sopenharmony_ci 121570af302Sopenharmony_ci for (size_t i = 0; i < SIZES_COUNT; i++) { 122570af302Sopenharmony_ci snprintf(test_results.threads[i], MAX_TID_LEN, "%d", thread_data[i].self_id); 123570af302Sopenharmony_ci } 124570af302Sopenharmony_ci stats_to_buffer(test_results.stats_after_allocations); 125570af302Sopenharmony_ci 126570af302Sopenharmony_ci pthread_barrier_wait(&free_barrier); 127570af302Sopenharmony_ci for (size_t i = 0; i < SIZES_COUNT; i++) { 128570af302Sopenharmony_ci pthread_join(threads[i], NULL); 129570af302Sopenharmony_ci } 130570af302Sopenharmony_ci stats_to_buffer(test_results.stats_after_free); 131570af302Sopenharmony_ci return test_results; 132570af302Sopenharmony_ci} 133570af302Sopenharmony_ci 134570af302Sopenharmony_cistatic void *allocate_and_abandon(void *arg) 135570af302Sopenharmony_ci{ 136570af302Sopenharmony_ci void **allocs = arg; 137570af302Sopenharmony_ci for (size_t i = 0; i < SIZES_COUNT; i++) { 138570af302Sopenharmony_ci allocs[i] = malloc(sizes[i]); 139570af302Sopenharmony_ci } 140570af302Sopenharmony_ci return NULL; 141570af302Sopenharmony_ci} 142570af302Sopenharmony_ci 143570af302Sopenharmony_cistatic int validate_main_thread_test_results(test_results_t *test_results) 144570af302Sopenharmony_ci{ 145570af302Sopenharmony_ci malloc_thread_stats_t stats_before_allocations = {0}; 146570af302Sopenharmony_ci malloc_thread_stats_t stats_after_allocations = {0}; 147570af302Sopenharmony_ci malloc_thread_stats_t stats_after_free = {0}; 148570af302Sopenharmony_ci populate_thread_stats(test_results->stats_before_allocations, test_results->threads[0], &stats_before_allocations); 149570af302Sopenharmony_ci populate_thread_stats(test_results->stats_after_allocations, test_results->threads[0], &stats_after_allocations); 150570af302Sopenharmony_ci populate_thread_stats(test_results->stats_after_free, test_results->threads[0], &stats_after_free); 151570af302Sopenharmony_ci stats_after_free.total_mmapped_memory -= stats_before_allocations.total_mmapped_memory; 152570af302Sopenharmony_ci stats_after_free.total_allocated_memory -= stats_before_allocations.total_allocated_memory; 153570af302Sopenharmony_ci stats_after_free.mmapped_regions -= stats_before_allocations.mmapped_regions; 154570af302Sopenharmony_ci int result = validate_total_allocated(&stats_after_allocations); 155570af302Sopenharmony_ci result &= validate_all_freed(&stats_after_free); 156570af302Sopenharmony_ci return result; 157570af302Sopenharmony_ci} 158570af302Sopenharmony_ci 159570af302Sopenharmony_cistatic int validate_allocated_size(size_t size, malloc_thread_stats_t *stats) 160570af302Sopenharmony_ci{ 161570af302Sopenharmony_ci int result = expect_greater_equal(stats->total_allocated_memory, size, "allocated memory", "size"); 162570af302Sopenharmony_ci if (size > MMAP_THRESHOLD) { 163570af302Sopenharmony_ci result &= expect_greater_equal(stats->total_mmapped_memory, size, "mmapped memory", "size"); 164570af302Sopenharmony_ci result &= expect_equal(stats->mmapped_regions, 1, "mmapped regions"); 165570af302Sopenharmony_ci } 166570af302Sopenharmony_ci return result; 167570af302Sopenharmony_ci} 168570af302Sopenharmony_ci 169570af302Sopenharmony_cistatic int validate_different_threads_test_results(test_results_t *test_results) 170570af302Sopenharmony_ci{ 171570af302Sopenharmony_ci int result = 1; 172570af302Sopenharmony_ci for (size_t i = 0; i < SIZES_COUNT; i++) { 173570af302Sopenharmony_ci malloc_thread_stats_t thread_stats = {0}; 174570af302Sopenharmony_ci result &= populate_thread_stats(test_results->stats_after_allocations, test_results->threads[i], &thread_stats); 175570af302Sopenharmony_ci result &= validate_allocated_size(sizes[i], &thread_stats); 176570af302Sopenharmony_ci if (is_thread_in_output(test_results->stats_after_free, test_results->threads[i])) { 177570af302Sopenharmony_ci t_error("Thread %s did not disappear from output\n", test_results->threads[i]); 178570af302Sopenharmony_ci result = 0; 179570af302Sopenharmony_ci } 180570af302Sopenharmony_ci } 181570af302Sopenharmony_ci 182570af302Sopenharmony_ci long long free_heap_space_after_allocations = 0; 183570af302Sopenharmony_ci long long free_heap_space_after_free = 0; 184570af302Sopenharmony_ci result &= populate_total_free_heap_space(test_results->stats_after_allocations, &free_heap_space_after_allocations); 185570af302Sopenharmony_ci result &= populate_total_free_heap_space(test_results->stats_after_free, &free_heap_space_after_free); 186570af302Sopenharmony_ci result &= expect_greater_equal( 187570af302Sopenharmony_ci free_heap_space_after_free, 188570af302Sopenharmony_ci free_heap_space_after_allocations, 189570af302Sopenharmony_ci "free heap space after free", 190570af302Sopenharmony_ci "free heap space after allocations"); 191570af302Sopenharmony_ci return result; 192570af302Sopenharmony_ci} 193570af302Sopenharmony_ci 194570af302Sopenharmony_cistatic int validate_and_report( 195570af302Sopenharmony_ci test_results_t *test_results, 196570af302Sopenharmony_ci int (*validate_test_results_func)(test_results_t *), 197570af302Sopenharmony_ci const char *message) 198570af302Sopenharmony_ci{ 199570af302Sopenharmony_ci t_printf("%s...", message); 200570af302Sopenharmony_ci if (!validate_test_results_func(test_results)) { 201570af302Sopenharmony_ci t_error("Failed!\n"); 202570af302Sopenharmony_ci return 0; 203570af302Sopenharmony_ci } 204570af302Sopenharmony_ci t_printf("Success\n"); 205570af302Sopenharmony_ci return 1; 206570af302Sopenharmony_ci} 207570af302Sopenharmony_ci 208570af302Sopenharmony_ciint main(void) 209570af302Sopenharmony_ci{ 210570af302Sopenharmony_ci test_results_t main_thread_test_results = get_main_thread_test_results(); 211570af302Sopenharmony_ci test_results_t different_threads_test_results = get_different_threads_test_results(); 212570af302Sopenharmony_ci int result = validate_and_report( 213570af302Sopenharmony_ci &main_thread_test_results, 214570af302Sopenharmony_ci validate_main_thread_test_results, 215570af302Sopenharmony_ci "Testing allocations in main thread"); 216570af302Sopenharmony_ci result &= validate_and_report( 217570af302Sopenharmony_ci &different_threads_test_results, 218570af302Sopenharmony_ci validate_different_threads_test_results, 219570af302Sopenharmony_ci "Testing allocations in different threads"); 220570af302Sopenharmony_ci return result == 0; 221570af302Sopenharmony_ci} 222570af302Sopenharmony_ci 223570af302Sopenharmony_ci#endif // TEST_MALLOC_STATS_H 224