1/*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *    http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef TEST_MALLOC_STATS_COMMON_H
17#define TEST_MALLOC_STATS_COMMON_H
18
19#define _GNU_SOURCE
20
21#include <unistd.h>
22#include <sys/syscall.h>
23#include <stddef.h>
24#include <pthread.h>
25#include <malloc.h>
26#include "test.h"
27
28#define SIZES_COUNT 10
29#define SIZE_ALIGN (8 * sizeof(size_t))
30#define MMAP_THRESHOLD ((0x1c00 * SIZE_ALIGN) - OVERHEAD)
31#define LIST_OVERHEAD (2 * sizeof(void *))
32#define OVERHEAD (sizeof(size_t) + LIST_OVERHEAD)
33
34static size_t sizes[SIZES_COUNT] = {
35	23,
36	32,
37	256,
38	3072,
39	3584,
40	262144,
41	327680,
42	8 * 1024 * 1024,
43	16 * 1024 * 1024,
44	32 * 1024 * 1024
45};
46
47typedef struct {
48	long long mmapped_regions;
49	long long total_mmapped_memory;
50	long long total_allocated_memory;
51} malloc_thread_stats_t;
52
53typedef struct {
54	size_t alloc_size;
55	pthread_barrier_t *alloc_barrier;
56	pthread_barrier_t *free_barrier;
57	pid_t self_id;
58} thread_data_t;
59
60static malloc_thread_stats_t get_total_from_test_sizes()
61{
62	malloc_thread_stats_t total_stats = {0};
63	for (size_t i = 0; i < SIZES_COUNT; i++) {
64		if (sizes[i] > MMAP_THRESHOLD) {
65			total_stats.total_mmapped_memory += sizes[i];
66			total_stats.mmapped_regions++;
67		}
68		total_stats.total_allocated_memory += sizes[i];
69	}
70	return total_stats;
71}
72
73static int expect_greater_equal(long long amt1, long long amt2, const char *amt1_name, const char *amt2_name)
74{
75	if (amt1 >= amt2) {
76		return 1;
77	}
78	t_error("Expected %s(value: %lld) to be >= %s(value: %lld)\n", amt1_name, amt1, amt2_name, amt2);
79	return 0;
80}
81
82static int expect_equal(long long amt, long long value, const char *amt_name)
83{
84	if (amt == value) {
85		return 1;
86	}
87	t_error("Expected %s(value: %lld) to be %lld\n", amt_name, amt, value);
88	return 0;
89}
90
91static int validate_total_allocated(malloc_thread_stats_t *total_stats)
92{
93	malloc_thread_stats_t total_from_test_sizes = get_total_from_test_sizes();
94
95	int result = expect_greater_equal(
96		total_stats->total_allocated_memory,
97		total_from_test_sizes.total_allocated_memory,
98		"allocated memory",
99		"total memory from test sizes");
100	result &= expect_greater_equal(
101		total_stats->total_mmapped_memory,
102		total_from_test_sizes.total_mmapped_memory,
103		"mmapped memory",
104		"total large memory from test sizes");
105	result &= expect_equal(
106		total_stats->mmapped_regions,
107		total_from_test_sizes.mmapped_regions,
108		"mmapped regions");
109	return result;
110}
111
112static int validate_all_freed(malloc_thread_stats_t *total_stats)
113{
114	int result = expect_equal(total_stats->total_allocated_memory, 0, "allocated memory");
115	result &= expect_equal(total_stats->total_mmapped_memory, 0, "mmapped memory");
116	result &= expect_equal(total_stats->mmapped_regions, 0, "mmapped regions");
117	return result;
118}
119
120static void *allocate_wait_free(void *arg)
121{
122	thread_data_t *thread_data = arg;
123	thread_data->self_id = syscall(__NR_gettid);
124	void *alloc = malloc(thread_data->alloc_size);
125	pthread_barrier_wait(thread_data->alloc_barrier);
126	pthread_barrier_wait(thread_data->free_barrier);
127	free(alloc);
128	return NULL;
129}
130
131#endif // TEST_MALLOC_STATS_COMMON_H
132