comparison read_cache.c @ 225:9b1b740e3fc9 src

big build system changes * cleaned up all Makefiles and added a Makefile.common * added relchk script * moved libdvdread files to a dvdread subdir * moved DVD VM to a vm subdir * removed unused code in read_cache.c
author mroi
date Sun, 11 Jan 2004 21:43:13 +0000
parents 7eda95524e83
children 065a2835ba90
comparison
equal deleted inserted replaced
224:f19fce15577b 225:9b1b740e3fc9
17 * along with this program; if not, write to the Free Software 17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 * 19 *
20 * $Id$ 20 * $Id$
21 * 21 *
22 */
23 /*
24 * There was a multithreaded read ahead cache in here for some time, but
25 * it had only been used for a short time. If you want to have a look at it,
26 * search the CVS attic.
22 */ 27 */
23 28
24 #ifdef HAVE_CONFIG_H 29 #ifdef HAVE_CONFIG_H
25 #include "config.h" 30 #include "config.h"
26 #endif 31 #endif
28 #include "dvdnav.h" 33 #include "dvdnav.h"
29 #include "read_cache.h" 34 #include "read_cache.h"
30 #include <pthread.h> 35 #include <pthread.h>
31 #include <sys/time.h> 36 #include <sys/time.h>
32 #include <time.h> 37 #include <time.h>
33
34
35 #define DVDNAV_PROFILE
36
37
38 /* Read-ahead cache structure. */
39 #if _MULTITHREAD_
40
41 /* For the multithreaded cache, the cache is a ring buffer + writing
42 * thread that continuously reads data into the buffer until it is
43 * full or the 'upper-bound' has been reached.
44 */
45
46 #define CACHE_BUFFER_SIZE 2048 /* Cache this number of blocks at a time */
47
48 struct read_cache_s {
49 pthread_mutex_t cache_lock;
50 pthread_t read_thread;
51
52 /* Buffer */
53 uint8_t *buffer;
54
55 /* Size of buffer */
56 int32_t size;
57 /* block offset from sector start of buffer 'head' */
58 uint32_t pos;
59 /* block offset from sector start of read point */
60 uint32_t read_point;
61 /* block offset from buffer start to ring-boundary */
62 uint32_t start;
63
64 /* Bit of strange cross-linking going on here :) -- Gotta love C :) */
65 dvdnav_t *dvd_self;
66 };
67
68 #else
69 38
70 #define READ_CACHE_CHUNKS 10 39 #define READ_CACHE_CHUNKS 10
71 40
72 /* all cache chunks must be memory aligned to allow use of raw devices */ 41 /* all cache chunks must be memory aligned to allow use of raw devices */
73 #define ALIGNMENT 2048 42 #define ALIGNMENT 2048
96 pthread_mutex_t lock; 65 pthread_mutex_t lock;
97 66
98 /* Bit of strange cross-linking going on here :) -- Gotta love C :) */ 67 /* Bit of strange cross-linking going on here :) -- Gotta love C :) */
99 dvdnav_t *dvd_self; 68 dvdnav_t *dvd_self;
100 }; 69 };
101 #endif
102 70
103 /* 71 /*
104 #define READ_CACHE_TRACE 0 72 #define READ_CACHE_TRACE 0
105 */ 73 */
106 74
120 # define dprintf(fmt, ...) /* Nowt */ 88 # define dprintf(fmt, ...) /* Nowt */
121 #endif /* _MSC_VER */ 89 #endif /* _MSC_VER */
122 # endif 90 # endif
123 #endif 91 #endif
124 92
125 #if _MULTITHREAD_
126
127 void * read_cache_read_thread (void * this_gen) {
128 int cont = 1;
129 int32_t diff, start;
130 uint32_t pos, size, startp, endp;
131 uint32_t s,c;
132 uint8_t *at;
133 read_cache_t *self = (read_cache_t*)this_gen;
134
135 while(cont) {
136
137 pthread_mutex_lock(&self->cache_lock);
138
139 if(self->size >= 0) {
140 diff = self->read_point - self->pos;
141 if(diff >= self->size/2) {
142 dprintf("(II) Read thread -- ");
143
144 startp = (self->start) % CACHE_BUFFER_SIZE;
145 endp = abs((self->start + diff - 1) % CACHE_BUFFER_SIZE);
146 dprintf("startp = %i, endp = %i -- ",startp, endp);
147
148 pos = self->pos + diff;
149 size = self->size - diff;
150 start = (self->start + diff) % CACHE_BUFFER_SIZE;
151
152 /* Fill remainder of buffer */
153
154 if(startp > endp) {
155 s = pos + size; c = CACHE_BUFFER_SIZE - startp;
156 at = self->buffer + (startp * DVD_VIDEO_LB_LEN);
157 if(c > 0) {
158 dprintf("(1) Reading from %i to %i to %i ", s, s+c-1, startp);
159 pthread_mutex_unlock(&self->cache_lock);
160 DVDReadBlocks(self->dvd_self->file, s,c, at);
161 pthread_mutex_lock(&self->cache_lock);
162 }
163
164 s = pos + size + c; c = CACHE_BUFFER_SIZE - size - c;
165 at = self->buffer;
166 if(c > 0) {
167 dprintf("(2) Reading from %i to %i to %i ", s, s+c-1, 0);
168 pthread_mutex_unlock(&self->cache_lock);
169 DVDReadBlocks(self->dvd_self->file, s,c, at);
170 pthread_mutex_lock(&self->cache_lock);
171 }
172 } else {
173 s = pos + size; c = CACHE_BUFFER_SIZE - size;
174 at = self->buffer + (startp * DVD_VIDEO_LB_LEN);
175 if(c > 0) {
176 dprintf("(3) Reading from %i to %i to %i ", s, s+c-1, startp);
177 pthread_mutex_unlock(&self->cache_lock);
178 DVDReadBlocks(self->dvd_self->file, s,c, at);
179 pthread_mutex_lock(&self->cache_lock);
180 }
181 }
182
183 dprintf("\n");
184
185 self->pos = pos;
186 self->start = start; self->size = CACHE_BUFFER_SIZE;
187 }
188 }
189
190 pthread_mutex_unlock(&self->cache_lock);
191 cont = (self->buffer != NULL);
192 usleep(100);
193 }
194
195 return NULL;
196 }
197
198 read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self) {
199 read_cache_t *me;
200
201 me = (read_cache_t*)malloc(sizeof(struct read_cache_s));
202
203 if(me) {
204 int err;
205
206 me->dvd_self = dvd_self;
207 me->buffer = (uint8_t*)malloc(CACHE_BUFFER_SIZE * DVD_VIDEO_LB_LEN);
208 me->start = 0;
209 me->pos = 0;
210 me->read_point = 0;
211 me->size = -1;
212
213 /* Initialise the mutex */
214 pthread_mutex_init(&me->cache_lock, NULL);
215
216 if ((err = pthread_create (&me->read_thread,
217 NULL, read_cache_read_thread, me)) != 0) {
218 dprintf("read_cache: can't create new thread (%s)\n",strerror(err));
219 }
220 }
221
222 return me;
223 }
224
225 void dvdnav_read_cache_free(read_cache_t* self) {
226 dvdnav_t *tmp;
227
228 pthread_mutex_lock(&self->cache_lock);
229
230 if(self->buffer) {
231 free(self->buffer);
232 self->buffer = NULL;
233 self->size = -2;
234 }
235
236 pthread_mutex_unlock(&self->cache_lock);
237
238 pthread_join(self->read_thread, NULL);
239
240 pthread_mutex_destroy(&self->cache_lock);
241
242 tmp = self->dvd_self;
243 free(self);
244
245 /* We free the main structure, too, because we have no buffers out there. */
246 free(tmp);
247 }
248
249 /* This function MUST be called whenever self->file changes. */
250 void dvdnav_read_cache_clear(read_cache_t *self) {
251 if(!self)
252 return;
253
254 pthread_mutex_lock(&self->cache_lock);
255 self->size = -1;
256 self->start = 0;
257 self->pos = 0;
258 self->read_point = 0;
259 pthread_mutex_unlock(&self->cache_lock);
260 }
261
262 /* This function is called just after reading the NAV packet. */
263 void dvdnav_pre_cache_blocks(read_cache_t *self, int sector, size_t block_count) {
264 if(!self)
265 return;
266
267 if(!self->dvd_self->use_read_ahead) {
268 return;
269 }
270
271 pthread_mutex_lock(&self->cache_lock);
272 dprintf("Requested pre-cache (%i -> +%i) : current state pos=%i, size=%i.\n",
273 sector, block_count, self->pos, self->size);
274
275 /* Are the contents of the buffer in any way relevant? */
276 if((self->size > 0) && (sector >= self->pos) && (sector <= self->pos+self->size)) {
277 dprintf("Contents relevant ... adjusting\n");
278 self->read_point = sector;
279 } else {
280 /* Flush the cache as its not much use */
281 dprintf("Contents irrelevent... flushing\n");
282 self->size = 0;
283 self->start = 0;
284 self->pos = sector;
285 self->read_point = sector;
286 }
287
288 pthread_mutex_unlock(&self->cache_lock);
289 }
290
291 /* This function will do the cache read */
292 int dvdnav_read_cache_block( read_cache_t *self, int sector, size_t block_count, uint8_t **buf) {
293 int result, diff;
294
295 if(!self)
296 return 0;
297
298 pthread_mutex_lock(&self->cache_lock);
299 dprintf("Read from %i -> +%i (buffer pos=%i, read_point=%i, size=%i)... ", sector, block_count,
300 self->pos, self->read_point, self->size);
301 if((self->size > 0) && (sector >= self->read_point) &&
302 (sector + block_count <= self->pos + self->size)) {
303 /* Hit */
304
305 /* Drop any skipped blocks */
306 diff = sector - self->read_point;
307 if(diff > 0)
308 self->read_point += diff;
309
310 diff = self->read_point - self->pos;
311
312 if(((self->start + diff) % CACHE_BUFFER_SIZE) + block_count <= CACHE_BUFFER_SIZE) {
313 dprintf("************** Single read\n");
314 memcpy(*buf, self->buffer + (((self->start + diff) % CACHE_BUFFER_SIZE) * DVD_VIDEO_LB_LEN),
315 block_count * DVD_VIDEO_LB_LEN);
316 self->read_point += block_count;
317 pthread_mutex_unlock(&self->cache_lock);
318
319 return (int)block_count;
320 } else {
321 int32_t boundary = CACHE_BUFFER_SIZE - self->start;
322
323 dprintf("************** Multiple read\n");
324 memcpy(*buf, self->buffer + (((self->start + diff) % CACHE_BUFFER_SIZE) * DVD_VIDEO_LB_LEN),
325 boundary * DVD_VIDEO_LB_LEN);
326 memcpy(*buf + (boundary * DVD_VIDEO_LB_LEN), self->buffer,
327 (block_count-boundary) * DVD_VIDEO_LB_LEN);
328 self->read_point += block_count;
329 pthread_mutex_unlock(&self->cache_lock);
330
331 return (int)block_count;
332 }
333 } else {
334 /* Miss */
335
336 fprintf(MSG_OUT, "libdvdnav: DVD read cache miss! (not bad but a performance hit) sector=%d\n", sector);
337 result = DVDReadBlocks( self->dvd_self->file, sector, block_count, *buf);
338 self->read_point = sector+block_count;
339 if(self->read_point > self->pos + self->size) {
340 /* Flush the cache as its not much use */
341 dprintf("Contents irrelevent... flushing\n");
342 self->size = 0;
343 self->start = 0;
344 self->pos = sector+block_count;
345 }
346 pthread_mutex_unlock(&self->cache_lock);
347 usleep(300);
348 return result;
349 }
350
351 /* Should never get here */
352 return 0;
353 }
354
355 dvdnav_status_t dvdnav_free_cache_block(dvdnav_t *self, unsigned char *buf) {
356 return DVDNAV_STATUS_OK;
357 }
358
359 #else
360 93
361 read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self) { 94 read_cache_t *dvdnav_read_cache_new(dvdnav_t* dvd_self) {
362 read_cache_t *self; 95 read_cache_t *self;
363 int i; 96 int i;
364 97
518 if (use >= 0) { 251 if (use >= 0) {
519 read_cache_chunk_t *chunk; 252 read_cache_chunk_t *chunk;
520 253
521 /* Increment read-ahead size if sector follows the last sector */ 254 /* Increment read-ahead size if sector follows the last sector */
522 if (sector == (self->last_sector + 1)) { 255 if (sector == (self->last_sector + 1)) {
523 self->read_ahead_incr++; 256 if (self->read_ahead_incr < READ_AHEAD_SIZE_MAX)
257 self->read_ahead_incr++;
524 } else { 258 } else {
525 self->read_ahead_size = READ_AHEAD_SIZE_MIN; 259 self->read_ahead_size = READ_AHEAD_SIZE_MIN;
526 self->read_ahead_incr = 0; 260 self->read_ahead_incr = 0;
527 } 261 }
528 self->last_sector = sector; 262 self->last_sector = sector;
537 read_ahead_buf = chunk->cache_buffer + chunk->cache_read_count * DVD_VIDEO_LB_LEN; 271 read_ahead_buf = chunk->cache_buffer + chunk->cache_read_count * DVD_VIDEO_LB_LEN;
538 *buf = chunk->cache_buffer + (sector - chunk->cache_start_sector) * DVD_VIDEO_LB_LEN; 272 *buf = chunk->cache_buffer + (sector - chunk->cache_start_sector) * DVD_VIDEO_LB_LEN;
539 chunk->usage_count++; 273 chunk->usage_count++;
540 pthread_mutex_unlock(&self->lock); 274 pthread_mutex_unlock(&self->lock);
541 275
542 /* Read blocks if needed */ 276 dprintf("libdvdnav: sector=%d, start_sector=%d, last_sector=%d\n", sector, chunk->cache_start_sector, chunk->cache_start_sector + chunk->cache_block_count);
543 if (sector >= (chunk->cache_start_sector + chunk->cache_read_count)) { 277
544 278 /* read_ahead_size */
545 dprintf("libdvdnav: sector=%d, start_sector=%d, last_sector=%d\n", sector, chunk->cache_start_sector, chunk->cache_start_sector + chunk->cache_block_count); 279 incr = self->read_ahead_incr >> 1;
546 280 if ((self->read_ahead_size + incr) > READ_AHEAD_SIZE_MAX) {
547 /* read_ahead_size */ 281 self->read_ahead_size = READ_AHEAD_SIZE_MAX;
548 incr = self->read_ahead_incr >> 1; 282 } else {
549 if ((self->read_ahead_size + incr) > READ_AHEAD_SIZE_MAX) { 283 self->read_ahead_size += incr;
550 self->read_ahead_size = READ_AHEAD_SIZE_MAX; 284 }
551 } else { 285
552 self->read_ahead_size = self->read_ahead_size + incr; 286 /* real read size */
553 } 287 start = chunk->cache_start_sector + chunk->cache_read_count;
554 self->read_ahead_incr = 0; 288 if (chunk->cache_read_count + self->read_ahead_size > chunk->cache_block_count) {
555 289 size = chunk->cache_block_count - chunk->cache_read_count;
556 /* real read size */ 290 } else {
557 start = chunk->cache_start_sector + chunk->cache_read_count; 291 size = self->read_ahead_size;
558 if (chunk->cache_read_count + self->read_ahead_size > chunk->cache_block_count) { 292 /* ensure that the sector we want will be read */
559 size = chunk->cache_block_count - chunk->cache_read_count; 293 if (sector >= chunk->cache_start_sector + chunk->cache_read_count + size)
560 } else { 294 size = sector - chunk->cache_start_sector - chunk->cache_read_count;
561 size = self->read_ahead_size; 295 }
562 } 296 dprintf("libdvdnav: read_ahead_size=%d, size=%d\n", self->read_ahead_size, size);
563 dprintf("libdvdnav: read_ahead_size=%d, size=%d\n", self->read_ahead_size, size); 297
564 298 if (size)
565 chunk->cache_read_count += DVDReadBlocks(self->dvd_self->file, 299 chunk->cache_read_count += DVDReadBlocks(self->dvd_self->file,
566 start, 300 start,
567 size, 301 size,
568 read_ahead_buf); 302 read_ahead_buf);
569 }
570 303
571 res = DVD_VIDEO_LB_LEN * block_count; 304 res = DVD_VIDEO_LB_LEN * block_count;
572 305
573 } else { 306 } else {
574 307
609 /* when we want to dispose the cache, try freeing it now */ 342 /* when we want to dispose the cache, try freeing it now */
610 dvdnav_read_cache_free(cache); 343 dvdnav_read_cache_free(cache);
611 344
612 return DVDNAV_STATUS_OK; 345 return DVDNAV_STATUS_OK;
613 } 346 }
614
615 #endif