1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkChunkAlloc.h"
9 #include "SkUtils.h"
10 #include "Test.h"
11 
check_alloc(skiatest::Reporter * reporter,const SkChunkAlloc & alloc,size_t capacity,size_t used,int numBlocks)12 static void check_alloc(skiatest::Reporter* reporter, const SkChunkAlloc& alloc,
13                         size_t capacity, size_t used, int numBlocks) {
14     REPORTER_ASSERT(reporter, alloc.totalCapacity() >= capacity);
15     REPORTER_ASSERT(reporter, alloc.totalUsed() == used);
16     SkDEBUGCODE(REPORTER_ASSERT(reporter, alloc.blockCount() == numBlocks);)
17 }
18 
simple_alloc(skiatest::Reporter * reporter,SkChunkAlloc * alloc,size_t size)19 static void* simple_alloc(skiatest::Reporter* reporter, SkChunkAlloc* alloc, size_t size) {
20     void* ptr = alloc->allocThrow(size);
21     check_alloc(reporter, *alloc, size, size, 1);
22     REPORTER_ASSERT(reporter, alloc->contains(ptr));
23     return ptr;
24 }
25 
test_chunkalloc(skiatest::Reporter * reporter)26 static void test_chunkalloc(skiatest::Reporter* reporter) {
27     static const size_t kMin = 1024;
28     SkChunkAlloc alloc(kMin);
29 
30     //------------------------------------------------------------------------
31     // check empty
32     check_alloc(reporter, alloc, 0, 0, 0);
33     REPORTER_ASSERT(reporter, !alloc.contains(nullptr));
34     REPORTER_ASSERT(reporter, !alloc.contains(reporter));
35 
36     // reset on empty allocator
37     alloc.reset();
38     check_alloc(reporter, alloc, 0, 0, 0);
39 
40     // rewind on empty allocator
41     alloc.rewind();
42     check_alloc(reporter, alloc, 0, 0, 0);
43 
44     //------------------------------------------------------------------------
45     // test reset when something is allocated
46     size_t size = kMin >> 1;
47     void* ptr = simple_alloc(reporter, &alloc, size);
48 
49     alloc.reset();
50     check_alloc(reporter, alloc, 0, 0, 0);
51     REPORTER_ASSERT(reporter, !alloc.contains(ptr));
52 
53     //------------------------------------------------------------------------
54     // test rewind when something is allocated
55     ptr = simple_alloc(reporter, &alloc, size);
56 
57     alloc.rewind();
58     check_alloc(reporter, alloc, size, 0, 1);
59     REPORTER_ASSERT(reporter, !alloc.contains(ptr));
60 
61     // use the available block
62     ptr = simple_alloc(reporter, &alloc, size);
63     alloc.reset();
64 
65     //------------------------------------------------------------------------
66     // test out allocating a second block
67     ptr = simple_alloc(reporter, &alloc, size);
68 
69     ptr = alloc.allocThrow(kMin);
70     check_alloc(reporter, alloc, 2*kMin, size+kMin, 2);
71     REPORTER_ASSERT(reporter, alloc.contains(ptr));
72 
73     //------------------------------------------------------------------------
74     // test out unalloc
75     size_t freed = alloc.unalloc(ptr);
76     REPORTER_ASSERT(reporter, freed == kMin);
77     check_alloc(reporter, alloc, 2*kMin, size, 2);
78     REPORTER_ASSERT(reporter, !alloc.contains(ptr));
79 }
80 
81 ///////////////////////////////////////////////////////////////////////////////
82 
set_zero(void * dst,size_t bytes)83 static void set_zero(void* dst, size_t bytes) {
84     char* ptr = (char*)dst;
85     for (size_t i = 0; i < bytes; ++i) {
86         ptr[i] = 0;
87     }
88 }
89 
90 #define MAX_ALIGNMENT   64
91 #define MAX_COUNT       ((MAX_ALIGNMENT) * 32)
92 #define PAD             32
93 #define TOTAL           (PAD + MAX_ALIGNMENT + MAX_COUNT + PAD)
94 
95 #define VALUE16         0x1234
96 #define VALUE32         0x12345678
97 
compare16(skiatest::Reporter * r,const uint16_t base[],uint16_t value,int count)98 static void compare16(skiatest::Reporter* r, const uint16_t base[],
99                       uint16_t value, int count) {
100     for (int i = 0; i < count; ++i) {
101         if (base[i] != value) {
102             ERRORF(r, "[%d] expected %x found %x\n", i, value, base[i]);
103             return;
104         }
105     }
106 }
107 
compare32(skiatest::Reporter * r,const uint32_t base[],uint32_t value,int count)108 static void compare32(skiatest::Reporter* r, const uint32_t base[],
109                       uint32_t value, int count) {
110     for (int i = 0; i < count; ++i) {
111         if (base[i] != value) {
112             ERRORF(r, "[%d] expected %x found %x\n", i, value, base[i]);
113             return;
114         }
115     }
116 }
117 
test_16(skiatest::Reporter * reporter)118 static void test_16(skiatest::Reporter* reporter) {
119     uint16_t buffer[TOTAL];
120 
121     for (int count = 0; count < MAX_COUNT; ++count) {
122         for (int alignment = 0; alignment < MAX_ALIGNMENT; ++alignment) {
123             set_zero(buffer, sizeof(buffer));
124 
125             uint16_t* base = &buffer[PAD + alignment];
126             sk_memset16(base, VALUE16, count);
127 
128             compare16(reporter, buffer,       0,       PAD + alignment);
129             compare16(reporter, base,         VALUE16, count);
130             compare16(reporter, base + count, 0,       TOTAL - count - PAD - alignment);
131         }
132     }
133 }
134 
test_32(skiatest::Reporter * reporter)135 static void test_32(skiatest::Reporter* reporter) {
136     uint32_t buffer[TOTAL];
137 
138     for (int count = 0; count < MAX_COUNT; ++count) {
139         for (int alignment = 0; alignment < MAX_ALIGNMENT; ++alignment) {
140             set_zero(buffer, sizeof(buffer));
141 
142             uint32_t* base = &buffer[PAD + alignment];
143             sk_memset32(base, VALUE32, count);
144 
145             compare32(reporter, buffer,       0,       PAD + alignment);
146             compare32(reporter, base,         VALUE32, count);
147             compare32(reporter, base + count, 0,       TOTAL - count - PAD - alignment);
148         }
149     }
150 }
151 
152 /**
153  *  Test sk_memset16 and sk_memset32.
154  *  For performance considerations, implementations may take different paths
155  *  depending on the alignment of the dst, and/or the size of the count.
156  */
DEF_TEST(Memset,reporter)157 DEF_TEST(Memset, reporter) {
158     test_16(reporter);
159     test_32(reporter);
160 
161     test_chunkalloc(reporter);
162 }
163