1/* Copyright (c) 2018, MariaDB Corporation Ab.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15
16/*
17 Checks that my_likely/my_unlikely is correctly used
18
19 Note that we can't use mysql_mutex or my_malloc here as these
20 uses likely() macros and the likely_mutex would be used twice
21*/
22
23#include "mysys_priv.h"
24#include <hash.h>
25#include <m_ctype.h>
26
27#ifndef CHECK_UNLIKEY
28my_bool likely_inited= 0;
29
30typedef struct st_likely_entry
31{
32 const char *key;
33 size_t key_length;
34 uint line;
35 ulonglong ok,fail;
36} LIKELY_ENTRY;
37
38static uchar *get_likely_key(LIKELY_ENTRY *part, size_t *length,
39 my_bool not_used __attribute__((unused)))
40{
41 *length= part->key_length;
42 return (uchar*) part->key;
43}
44
45pthread_mutex_t likely_mutex;
46HASH likely_hash;
47
48void init_my_likely()
49{
50 /* Allocate big enough to avoid malloc calls */
51 my_hash_init2(&likely_hash, 10000, &my_charset_bin,
52 1024, 0, 0,
53 (my_hash_get_key) get_likely_key, 0,
54 free, HASH_UNIQUE);
55 likely_inited= 1;
56 pthread_mutex_init(&likely_mutex, MY_MUTEX_INIT_FAST);
57}
58
59static int likely_cmp(LIKELY_ENTRY **a, LIKELY_ENTRY **b)
60{
61 int cmp;
62 if ((cmp= strcmp((*a)->key, (*b)->key)))
63 return cmp;
64 return (int) ((*a)->line - (*b)->line);
65}
66
67
68void end_my_likely(FILE *out)
69{
70 uint i;
71 FILE *likely_file;
72 my_bool do_close= 0;
73 LIKELY_ENTRY **sort_ptr= 0;
74
75 likely_inited= 0;
76
77 if (!(likely_file= out))
78 {
79 char name[80];
80 sprintf(name, "/tmp/unlikely-%lu.out", (ulong) getpid());
81 if ((likely_file= my_fopen(name, O_TRUNC | O_WRONLY, MYF(MY_WME))))
82 do_close= 1;
83 else
84 likely_file= stderr;
85 }
86 fflush(likely_file);
87 fputs("Wrong likely/unlikely usage:\n", likely_file);
88 if (!(sort_ptr= (LIKELY_ENTRY**)
89 malloc(sizeof(LIKELY_ENTRY*) *likely_hash.records)))
90 {
91 fprintf(stderr, "ERROR: Out of memory in end_my_likely\n");
92 goto err;
93 }
94
95 for (i=0 ; i < likely_hash.records ; i++)
96 sort_ptr[i]= (LIKELY_ENTRY *) my_hash_element(&likely_hash, i);
97
98 my_qsort(sort_ptr, likely_hash.records, sizeof(LIKELY_ENTRY*),
99 (qsort_cmp) likely_cmp);
100
101 for (i=0 ; i < likely_hash.records ; i++)
102 {
103 LIKELY_ENTRY *entry= sort_ptr[i];
104 if (entry->fail > entry->ok)
105 fprintf(likely_file,
106 "%50s line: %6u ok: %8lld fail: %8lld\n",
107 entry->key, entry->line, entry->ok, entry->fail);
108 }
109 fputs("\n", likely_file);
110 fflush(likely_file);
111err:
112 free((void*) sort_ptr);
113 if (do_close)
114 my_fclose(likely_file, MYF(MY_WME));
115 pthread_mutex_destroy(&likely_mutex);
116 my_hash_free(&likely_hash);
117}
118
119
120static LIKELY_ENTRY *my_likely_find(const char *file_name, uint line)
121{
122 char key[80], *pos;
123 LIKELY_ENTRY *entry;
124 size_t length;
125
126 if (!likely_inited)
127 return 0;
128
129 pos= strnmov(key, file_name, sizeof(key)-4);
130 int3store(pos+1, line);
131 length= (size_t) (pos-key)+4;
132
133 pthread_mutex_lock(&likely_mutex);
134 if (!(entry= (LIKELY_ENTRY*) my_hash_search(&likely_hash, (uchar*) key,
135 length)))
136 {
137 if (!(entry= (LIKELY_ENTRY *) malloc(sizeof(*entry) + length)))
138 return 0;
139 entry->key= (char*) (entry+1);
140 memcpy((void*) entry->key, key, length);
141 entry->key_length= length;
142 entry->line= line;
143 entry->ok= entry->fail= 0;
144
145 if (my_hash_insert(&likely_hash, (void*) entry))
146 {
147 pthread_mutex_unlock(&likely_mutex);
148 free(entry);
149 return 0;
150 }
151 }
152 pthread_mutex_unlock(&likely_mutex);
153 return entry;
154}
155
156
157int my_likely_ok(const char *file_name, uint line)
158{
159 LIKELY_ENTRY *entry= my_likely_find(file_name, line);
160 if (entry)
161 entry->ok++;
162 return 0;
163}
164
165
166int my_likely_fail(const char *file_name, uint line)
167{
168 LIKELY_ENTRY *entry= my_likely_find(file_name, line);
169 if (entry)
170 entry->fail++;
171 return 0;
172}
173#endif /* CHECK_UNLIKEY */
174