Skip to content

Commit 4c9fc4a

Browse files
committed
prefetch: Introduce basic readahead prefetch
Signed-off-by: Michael Lyulko <michael.lyulko@huawei.com> Signed-off-by: Shai Fultheim <shai.fultheim@huawei.com> Signed-off-by: Ido Ben Tsion <ido.ben.tsion@huawei.com> Signed-off-by: Robert Baldyga <robert.baldyga@unvertical.com>
1 parent f9866cf commit 4c9fc4a

33 files changed

Lines changed: 727 additions & 27 deletions

inc/ocf_cache.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ struct ocf_cache_info {
8080
ocf_promotion_t promotion_policy;
8181
/*!< Promotion policy selected */
8282

83+
ocf_pf_mask_t prefetch_mask;
84+
/*!< Prefetchers selected (bitmask) */
85+
8386
ocf_cache_line_size_t cache_line_size;
8487
/*!< Cache line size in KiB */
8588

inc/ocf_def.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ typedef enum {
346346
/**
347347
* Maximum numbers of IO classes per cache instance
348348
*/
349-
#define OCF_USER_IO_CLASS_MAX 33
349+
#define OCF_USER_IO_CLASS_MAX 34
350350
/**
351351
* Minimum value of a valid IO class ID
352352
*/

inc/ocf_err.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ typedef enum {
2828
/** Operation interrupted */
2929
OCF_ERR_INTR,
3030

31+
/** Busy */
32+
OCF_ERR_BUSY,
33+
3134
/** Operation not supported */
3235
OCF_ERR_NOT_SUPP,
3336

inc/ocf_mngt.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "ocf_cache.h"
1212
#include "ocf_core.h"
13+
#include "ocf_prefetch.h"
1314

1415
/**
1516
* @file
@@ -1005,6 +1006,31 @@ int ocf_mngt_cache_promotion_set_param(ocf_cache_t cache, ocf_promotion_t type,
10051006
int ocf_mngt_cache_promotion_get_param(ocf_cache_t cache, ocf_promotion_t type,
10061007
uint8_t param_id, uint32_t *param_value);
10071008

1009+
/**
1010+
* @brief Set prefetch policy in given cache
1011+
*
1012+
* @attention This changes only runtime state. To make changes persistent
1013+
* use function ocf_mngt_cache_save().
1014+
*
1015+
* @param[in] cache Cache handle
1016+
* @param[in] mask Bitmask of prefetch policies to enable
1017+
*
1018+
* @retval 0 Policy has been set successfully
1019+
* @retval Non-zero Error occurred and policy has not been set
1020+
*/
1021+
int ocf_mngt_cache_prefetch_set_policy(ocf_cache_t cache, ocf_pf_mask_t mask);
1022+
1023+
/**
1024+
* @brief Get prefetch policy in given cache
1025+
*
1026+
* @param[in] cache Cache handle
1027+
* @param[out] mask Bitmask of enabled prefetch policies
1028+
*
1029+
* @retval 0 success
1030+
* @retval Non-zero Error occurred and policy could not be retrieved
1031+
*/
1032+
int ocf_mngt_cache_prefetch_get_policy(ocf_cache_t cache, ocf_pf_mask_t *mask);
1033+
10081034
/**
10091035
* @brief IO class configuration
10101036
*/

inc/ocf_prefetch.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright(c) 2021-2024 Huawei Technologies Co., Ltd.
3+
* Copyright(c) 2026 Unvertical
4+
* SPDX-License-Identifier: BSD-3-Clause
5+
*/
6+
7+
#ifndef __OCF_PREFETCH_H__
8+
#define __OCF_PREFETCH_H__
9+
10+
#include "ocf_def.h"
11+
12+
/*
13+
* Prefetch Algorithm ID
14+
*/
15+
typedef enum {
16+
ocf_pf_none = -1,
17+
ocf_pf_readahead = 0,
18+
ocf_pf_num,
19+
} ocf_pf_id_t;
20+
21+
typedef uint8_t ocf_pf_mask_t;
22+
23+
/* The bitmask must fit all the values of ocf_pf_id_t */
24+
_Static_assert(OCF_BITWIDTH(ocf_pf_mask_t) >= ocf_pf_num);
25+
26+
#define OCF_PF_MASK_DEFAULT 0
27+
28+
#endif /* __OCF_PREFETCH_H__ */

inc/ocf_stats.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#ifndef __OCF_STATS_H__
1616
#define __OCF_STATS_H__
1717

18+
#include "ocf_prefetch.h"
19+
1820
/**
1921
* Entire row of statistcs
2022
*/
@@ -71,7 +73,11 @@ struct ocf_stats_usage {
7173
* ║ Pass-Through writes │ 0 │ 0.0 │ Requests ║
7274
* ║ Serviced requests │ 222 │ 100.0 │ Requests ║
7375
* ╟──────────────────────┼───────┼───────┼──────────╢
74-
* ║ Total requests │ 222 │ 100.0 │ Requests ║
76+
* ║ Prefetch: readahead │ 2 │ 0.0 │ Requests ║
77+
* ║ Prefetch total │ 2 │ 0.0 │ Requests ║
78+
* ╟──────────────────────┼───────┼───────┼──────────╢
79+
* ║ User requests │ 222 │ 100.0 │ Requests ║
80+
* ║ Total requests │ 224 │ 100.0 │ Requests ║
7581
* ╚══════════════════════╧═══════╧═══════╧══════════╝
7682
* </pre>
7783
*/
@@ -89,6 +95,8 @@ struct ocf_stats_requests {
8995
struct ocf_stat rd_pt;
9096
struct ocf_stat wr_pt;
9197
struct ocf_stat serviced;
98+
struct ocf_stat prefetch[ocf_pf_num];
99+
struct ocf_stat user;
92100
struct ocf_stat total;
93101
};
94102

@@ -127,6 +135,8 @@ struct ocf_stats_blocks {
127135
struct ocf_stat pass_through_rd;
128136
struct ocf_stat pass_through_wr;
129137
struct ocf_stat pass_through_total;
138+
struct ocf_stat prefetch_core_rd[ocf_pf_num];
139+
struct ocf_stat prefetch_cache_wr[ocf_pf_num];
130140
};
131141

132142
/**

src/engine/engine_common.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ static int lock_clines(struct ocf_request *req)
442442
* Caller must assure that request map info is up to date (request
443443
* is traversed).
444444
*/
445-
static inline void ocf_prepare_clines_miss(struct ocf_request *req)
445+
void ocf_prepare_clines_miss(struct ocf_request *req)
446446
{
447447
bool part_has_space;
448448

@@ -599,7 +599,7 @@ void ocf_engine_update_request_stats(struct ocf_request *req)
599599
{
600600
ocf_core_stats_request_update(req->core, req->part_id, req->rw,
601601
req->info.hit_no, req->core_line_count,
602-
req->is_deferred);
602+
req->io.pf_id, req->is_deferred);
603603
}
604604

605605
void inc_fallback_pt_error_counter(ocf_cache_t cache)

src/engine/engine_common.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,13 @@ struct ocf_engine_callbacks
223223
ocf_req_async_lock_cb resume;
224224
};
225225

226+
/**
227+
* @brief Prepare cache lines for miss request
228+
*
229+
* @param req OCF request
230+
*/
231+
void ocf_prepare_clines_miss(struct ocf_request *req);
232+
226233
/**
227234
* @brief Map and lock cachelines
228235
*

src/engine/engine_io.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright(c) 2024 Huawei Technologies
3+
* Copyright(c) 2026 Unvertical
34
* SPDX-License-Identifier: BSD-3-Clause
45
*/
56

@@ -131,7 +132,7 @@ void ocf_engine_forward_core_io_req(struct ocf_request *req,
131132
ocf_req_end_t callback)
132133
{
133134
ocf_core_stats_core_block_update(req->core, req->part_id, req->rw,
134-
req->bytes);
135+
req->bytes, req->io.pf_id);
135136

136137
ocf_req_forward_core_init(req, callback);
137138

@@ -143,7 +144,7 @@ void ocf_engine_forward_core_flush_req(struct ocf_request *req,
143144
ocf_req_end_t callback)
144145
{
145146
ocf_core_stats_core_block_update(req->core, req->part_id, req->rw,
146-
req->bytes);
147+
req->bytes, req->io.pf_id);
147148

148149
ocf_req_forward_core_init(req, callback);
149150

@@ -154,7 +155,7 @@ void ocf_engine_forward_core_discard_req(struct ocf_request *req,
154155
ocf_req_end_t callback)
155156
{
156157
ocf_core_stats_core_block_update(req->core, req->part_id, req->rw,
157-
req->bytes);
158+
req->bytes, req->io.pf_id);
158159

159160
ocf_req_forward_core_init(req, callback);
160161

src/engine/engine_prefetch.c

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/*
2+
* Copyright(c) 2012-2022 Intel Corporation
3+
* Copyright(c) 2022-2024 Huawei Technologies
4+
* Copyright(c) 2026 Unvertical
5+
* SPDX-License-Identifier: BSD-3-Clause
6+
*/
7+
8+
#include "ocf/ocf.h"
9+
#include "engine_prefetch.h"
10+
#include "engine_inv.h"
11+
#include "engine_bf.h"
12+
#include "engine_common.h"
13+
#include "engine_io.h"
14+
#include "../ocf_cache_priv.h"
15+
#include "../concurrency/ocf_concurrency.h"
16+
#include "../ocf_request.h"
17+
#include "../utils/utils_cache_line.h"
18+
#include "../utils/utils_user_part.h"
19+
#include "../metadata/metadata.h"
20+
#include "../ocf_def_priv.h"
21+
22+
#define OCF_ENGINE_DEBUG_IO_NAME "prefetch"
23+
#include "engine_debug.h"
24+
25+
static void _ocf_prefetch_read_complete(struct ocf_request *req, int error)
26+
{
27+
OCF_DEBUG_RQ(req, "Prefetch read completion");
28+
29+
ocf_req_get(req);
30+
31+
if (error) {
32+
req->complete(req, error);
33+
34+
ctx_data_free(req->cache->owner, req->data);
35+
36+
ocf_core_stats_core_error_update(req->core, OCF_READ);
37+
38+
/* Invalidate metadata */
39+
ocf_engine_invalidate(req);
40+
41+
return;
42+
}
43+
44+
/* Pretend the data is the copy, so that it's used by the backfill */
45+
req->cp_data = req->data;
46+
req->data = NULL;
47+
48+
/* Complete request */
49+
req->complete(req, error);
50+
51+
ocf_engine_backfill(req);
52+
}
53+
54+
static int _ocf_prefetch_read_do(struct ocf_request *req)
55+
{
56+
struct ocf_alock *c = ocf_cache_line_concurrency(req->cache);
57+
58+
if (unlikely(ocf_engine_is_hit(req))) {
59+
ocf_req_unlock(c, req);
60+
req->complete(req, 0);
61+
return 0;
62+
}
63+
64+
if (req->info.dirty_any) {
65+
ocf_hb_req_prot_lock_rd(req);
66+
67+
/* Request is dirty need to clean request */
68+
ocf_engine_clean(req);
69+
70+
ocf_hb_req_prot_unlock_rd(req);
71+
return 0;
72+
}
73+
74+
req->data = ctx_data_alloc(ocf_cache_get_ctx(req->cache),
75+
OCF_DIV_ROUND_UP(req->bytes, PAGE_SIZE));
76+
if (!req->data) {
77+
ocf_req_unlock(c, req);
78+
req->complete(req, 0);
79+
return 0;
80+
}
81+
82+
ocf_hb_req_prot_lock_wr(req);
83+
84+
/* Set valid status bits map */
85+
ocf_set_valid_map_info(req);
86+
87+
if (ocf_engine_needs_repart(req)) {
88+
OCF_DEBUG_RQ(req, "Re-Part");
89+
90+
/* Probably some cache lines are assigned into wrong
91+
* partition. Need to move it to new one
92+
*/
93+
ocf_user_part_move(req);
94+
}
95+
96+
ocf_hb_req_prot_unlock_wr(req);
97+
98+
OCF_DEBUG_RQ(req, "Submit");
99+
100+
ocf_req_get(req);
101+
ocf_engine_forward_core_io_req(req, _ocf_prefetch_read_complete);
102+
103+
/* Update statistics */
104+
ocf_engine_update_request_stats(req);
105+
ocf_engine_update_block_stats(req);
106+
107+
/* Put OCF request - decrease reference counter */
108+
ocf_req_put(req);
109+
110+
return 0;
111+
}
112+
113+
int ocf_prefetch_read(struct ocf_request *req)
114+
{
115+
struct ocf_user_part *user_part = &req->cache->user_parts[req->part_id];
116+
struct ocf_alock *c = ocf_cache_line_concurrency(req->cache);
117+
ocf_cache_t cache = req->cache;
118+
int lock;
119+
120+
if (env_atomic_read(&cache->pending_read_misses_list_blocked)) {
121+
req->complete(req, -OCF_ERR_BUSY);
122+
return 0;
123+
}
124+
125+
req->engine_handler = _ocf_prefetch_read_do;
126+
127+
if (!ocf_user_part_is_enabled(user_part)) {
128+
req->complete(req, -OCF_ERR_BUSY);
129+
return 0;
130+
}
131+
132+
ocf_req_hash(req);
133+
134+
ocf_hb_req_prot_lock_wr(req);
135+
136+
ocf_engine_lookup(req);
137+
138+
if (unlikely(ocf_engine_is_hit(req))) {
139+
ocf_hb_req_prot_unlock_wr(req);
140+
req->complete(req, 0);
141+
return 0;
142+
}
143+
144+
ocf_prepare_clines_miss(req);
145+
if (unlikely(ocf_req_test_mapping_error(req))) {
146+
ocf_hb_req_prot_unlock_wr(req);
147+
req->complete(req, 0);
148+
return 0;
149+
}
150+
151+
lock = ocf_req_async_lock_wr(c, req, ocf_engine_on_resume);
152+
if (unlikely(lock < 0)) {
153+
ocf_hb_req_prot_unlock_wr(req);
154+
req->complete(req, 0);
155+
return 0;
156+
}
157+
158+
ocf_hb_req_prot_unlock_wr(req);
159+
160+
if (lock == OCF_LOCK_ACQUIRED)
161+
_ocf_prefetch_read_do(req);
162+
163+
return 0;
164+
}

0 commit comments

Comments
 (0)