1/* GLIB sliced memory - fast threaded memory chunk allocator
2 * Copyright (C) 2005 Tim Janik
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19#include <glib.h>
20#include <string.h>
21
22#define ALIGN(size, base)       ((base) * (gsize) (((size) + (base) - 1) / (base)))
23
24static gdouble parse_memsize (const gchar *cstring);
25static void    usage         (void);
26
27static void
28fill_memory (guint **mem,
29             guint   n,
30             guint   val)
31{
32  guint j, o = 0;
33  for (j = 0; j < n; j++)
34    mem[j][o] = val;
35}
36
37static guint64
38access_memory3 (guint  **mema,
39                guint  **memb,
40                guint  **memd,
41                guint    n,
42                guint64  repeats)
43{
44  guint64 accu = 0, i, j;
45  const guint o = 0;
46  for (i = 0; i < repeats; i++)
47    {
48      for (j = 1; j < n; j += 2)
49        memd[j][o] = mema[j][o] + memb[j][o];
50    }
51  for (i = 0; i < repeats; i++)
52    for (j = 0; j < n; j++)
53      accu += memd[j][o];
54  return accu;
55}
56
57static void
58touch_mem (guint64 block_size,
59           guint64 n_blocks,
60           guint64 repeats)
61{
62  guint64 j, accu, n = n_blocks;
63  GTimer *timer;
64  guint **memc;
65  guint **memb;
66  guint **mema = g_new (guint*, n);
67  for (j = 0; j < n; j++)
68    mema[j] = g_slice_alloc (block_size);
69  memb = g_new (guint*, n);
70  for (j = 0; j < n; j++)
71    memb[j] = g_slice_alloc (block_size);
72  memc = g_new (guint*, n);
73  for (j = 0; j < n; j++)
74    memc[j] = g_slice_alloc (block_size);
75
76  timer = g_timer_new();
77  fill_memory (mema, n, 2);
78  fill_memory (memb, n, 3);
79  fill_memory (memc, n, 4);
80  access_memory3 (mema, memb, memc, n, 3);
81  g_timer_start (timer);
82  accu = access_memory3 (mema, memb, memc, n, repeats);
83  g_timer_stop (timer);
84
85  g_print ("Access-time = %fs\n", g_timer_elapsed (timer, NULL));
86  g_assert (accu / repeats == (2 + 3) * n / 2 + 4 * n / 2);
87
88  for (j = 0; j < n; j++)
89    {
90      g_slice_free1 (block_size, mema[j]);
91      g_slice_free1 (block_size, memb[j]);
92      g_slice_free1 (block_size, memc[j]);
93    }
94  g_timer_destroy (timer);
95  g_free (mema);
96  g_free (memb);
97  g_free (memc);
98}
99
100static void
101usage (void)
102{
103  g_print ("Usage: slice-color <block-size> [memory-size] [repeats] [colorization]\n");
104}
105
106int
107main (int   argc,
108      char *argv[])
109{
110  guint64 block_size = 512, area_size = 1024 * 1024, n_blocks, repeats = 1000000;
111
112  if (argc > 1)
113    block_size = parse_memsize (argv[1]);
114  else
115    {
116      usage();
117      block_size = 512;
118    }
119  if (argc > 2)
120    area_size = parse_memsize (argv[2]);
121  if (argc > 3)
122    repeats = parse_memsize (argv[3]);
123  if (argc > 4)
124    g_slice_set_config (G_SLICE_CONFIG_COLOR_INCREMENT, parse_memsize (argv[4]));
125
126  /* figure number of blocks from block and area size.
127   * divide area by 3 because touch_mem() allocates 3 areas
128   */
129  n_blocks = area_size / 3 / ALIGN (block_size, sizeof (gsize) * 2);
130
131  /* basic sanity checks */
132  if (!block_size || !n_blocks || block_size >= area_size)
133    {
134      g_printerr ("Invalid arguments: block-size=%llu memory-size=%llu\n", block_size, area_size);
135      usage();
136      return 1;
137    }
138
139  g_printerr ("Will allocate and touch %llu blocks of %llu bytes (= %llu bytes) %llu times with color increment: 0x%08llx\n",
140              n_blocks, block_size, n_blocks * block_size, repeats, g_slice_get_config (G_SLICE_CONFIG_COLOR_INCREMENT));
141
142  touch_mem (block_size, n_blocks, repeats);
143
144  return 0;
145}
146
147static gdouble
148parse_memsize (const gchar *cstring)
149{
150  gchar *mem = g_strdup (cstring);
151  gchar *string = g_strstrip (mem);
152  guint l = strlen (string);
153  gdouble f = 0;
154  gchar *derr = NULL;
155  gdouble msize;
156
157  switch (l ? string[l - 1] : 0)
158    {
159    case 'k':   f = 1000;               break;
160    case 'K':   f = 1024;               break;
161    case 'm':   f = 1000000;            break;
162    case 'M':   f = 1024 * 1024;        break;
163    case 'g':   f = 1000000000;         break;
164    case 'G':   f = 1024 * 1024 * 1024; break;
165    }
166  if (f)
167    string[l - 1] = 0;
168  msize = g_ascii_strtod (string, &derr);
169  g_free (mem);
170  if (derr && *derr)
171    {
172      g_printerr ("failed to parse number at: %s\n", derr);
173      msize = 0;
174    }
175  if (f)
176    msize *= f;
177  return msize;
178}
179