-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
Copy pathAttributeAccessInterfaceCache.h
145 lines (127 loc) · 4.69 KB
/
AttributeAccessInterfaceCache.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
*
* Copyright (c) 2024 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <stddef.h>
#include <app/AttributeAccessInterface.h>
#include <lib/core/DataModelTypes.h>
namespace chip {
namespace app {
/**
* @brief Cache to make look-up of AttributeAccessInterface (AAI) instances faster.
*
* This cache makes use of the fact that looking-up AttributeAccessInterface
* instances is usually done in loops, during read/subscription wildcard
* expansion, and there is a significant amount of locality.
*
* This cache records both "used" (i.e. uses AAI) and the single last
* "unused" (i.e. does NOT use AAI) entries. Combining positive/negative
* lookup led to factor of ~10 reduction of AAI lookups in total for wildcard
* reads on chip-all-clusters-app, with a cache size of 1. Increasing the size did not
* significantly improve the performance.
*/
class AttributeAccessInterfaceCache
{
public:
enum class CacheResult
{
kCacheMiss,
kDefinitelyUnused,
kDefinitelyUsed
};
AttributeAccessInterfaceCache() { Invalidate(); }
/**
* @brief Invalidate the whole cache. Must be called every time list of AAI registrations changes.
*/
void Invalidate()
{
for (auto & entry : mCacheSlots)
{
entry.Invalidate();
}
mLastUnusedEntry.Invalidate();
}
/**
* @brief Mark that we know a given <`endpointId`, `clusterId`> uses AAI, with instance `attrInterface`
*/
void MarkUsed(EndpointId endpointId, ClusterId clusterId, AttributeAccessInterface * attrInterface)
{
GetCacheSlot(endpointId, clusterId)->Set(endpointId, clusterId, attrInterface);
}
/**
* @brief Mark that we know a given <`endpointId`, `clusterId`> does NOT use AAI.
*/
void MarkUnused(EndpointId endpointId, ClusterId clusterId) { mLastUnusedEntry.Set(endpointId, clusterId, nullptr); }
/**
* @brief Get the AttributeAccessInterface instance for a given <`endpointId`, `clusterId`>, if present in cache.
*
* @param endpointId - Endpoint ID to look-up.
* @param clusterId - Cluster ID to look-up.
* @param outAttributeAccess - If not null, and Get returns `kDefinitelyUsed`, then this is set to the instance pointer.
* @return a for whether the entry is actually used or not.
*/
CacheResult Get(EndpointId endpointId, ClusterId clusterId, AttributeAccessInterface ** outAttributeAccess)
{
if (mLastUnusedEntry.Matches(endpointId, clusterId))
{
return CacheResult::kDefinitelyUnused;
}
AttributeAccessCacheEntry * cacheSlot = GetCacheSlot(endpointId, clusterId);
if (cacheSlot->Matches(endpointId, clusterId) && (cacheSlot->accessor != nullptr))
{
if (outAttributeAccess != nullptr)
{
*outAttributeAccess = cacheSlot->accessor;
}
return CacheResult::kDefinitelyUsed;
}
return CacheResult::kCacheMiss;
}
private:
struct AttributeAccessCacheEntry
{
EndpointId endpointId = kInvalidEndpointId;
ClusterId clusterId = kInvalidClusterId;
AttributeAccessInterface * accessor = nullptr;
void Invalidate()
{
endpointId = kInvalidEndpointId;
clusterId = kInvalidClusterId;
accessor = nullptr;
}
void Set(EndpointId theEndpointId, ClusterId theClusterId, AttributeAccessInterface * theAccessor)
{
endpointId = theEndpointId;
clusterId = theClusterId;
accessor = theAccessor;
}
bool Matches(EndpointId theEndpointId, ClusterId theClusterId) const
{
return (endpointId == theEndpointId) && (clusterId == theClusterId);
}
};
AttributeAccessCacheEntry * GetCacheSlot(EndpointId endpointId, ClusterId clusterId)
{
(void) endpointId;
(void) clusterId;
return &mCacheSlots[0];
}
AttributeAccessCacheEntry mCacheSlots[1];
AttributeAccessCacheEntry mLastUnusedEntry;
};
} // namespace app
} // namespace chip