[xiph-commits] r15260 - in trunk/cdparanoia: . interface paranoia

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Thu Sep 4 12:02:49 PDT 2008


Author: xiphmont
Date: 2008-09-04 12:02:47 -0700 (Thu, 04 Sep 2008)
New Revision: 15260

Added:
   trunk/cdparanoia/cachetest.c
Removed:
   trunk/cdparanoia/paranoia/cachetest.c
Modified:
   trunk/cdparanoia/Makefile.in
   trunk/cdparanoia/interface/cdda_interface.h
   trunk/cdparanoia/interface/interface.c
   trunk/cdparanoia/interface/low_interface.h
   trunk/cdparanoia/main.c
   trunk/cdparanoia/paranoia/Makefile.in
   trunk/cdparanoia/paranoia/cdda_paranoia.h
   trunk/cdparanoia/paranoia/p_block.c
Log:
No, changed my mind again. Cachetest belongs in main app, not paranoia library.



Modified: trunk/cdparanoia/Makefile.in
===================================================================
--- trunk/cdparanoia/Makefile.in	2008-09-04 18:22:46 UTC (rev 15259)
+++ trunk/cdparanoia/Makefile.in	2008-09-04 19:02:47 UTC (rev 15260)
@@ -25,7 +25,7 @@
 LIBDIR=@libdir@
 PWD = $(shell pwd)
 
-OFILES = main.o report.o header.o buffering_write.o
+OFILES = main.o report.o header.o buffering_write.o cachetest.o
 
 export STATIC 
 export VERSION

Added: trunk/cdparanoia/cachetest.c
===================================================================
--- trunk/cdparanoia/cachetest.c	                        (rev 0)
+++ trunk/cdparanoia/cachetest.c	2008-09-04 19:02:47 UTC (rev 15260)
@@ -0,0 +1,725 @@
+/*
+ * Copyright: GNU Public License 2 applies
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * cdparanoia (C) 2008 Monty <monty at xiph.org>
+ *
+ */
+
+/* we can ask most drives what their various caches' sizes are, but no
+   drive will tell if it caches redbook data.  None should, many do,
+   and there's no way in (eg) MMC/ATAPI to tell a cdrom drive not to
+   cache when accessing audio.  SCSI drives have a FUA facility, but
+   it's not clear how many ignore it.  MMC does specify some cache
+   side effect as part of SET READ AHEAD, but it's not clear we can
+   rely on them.  For that reason, we need to empirically determine
+   cache size and strategy used for reads. */
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include "interface/cdda_interface.h"
+#include "paranoia/cdda_paranoia.h"
+#include "version.h"
+
+#define reportC(...) {if(progress){fprintf(progress, __VA_ARGS__);}	\
+    if(log){fprintf(log, __VA_ARGS__);}}
+#define printC(...) {if(progress){fprintf(progress, __VA_ARGS__);}}
+#define logC(...) {if(log){fprintf(log, __VA_ARGS__);}}
+
+static int time_drive(cdrom_drive *d, FILE *progress, FILE *log, int lba, int len){
+  int i,j,x;
+  int latency[len];
+  int sectors[len];
+  double sum=0;
+  double sumsq=0;
+  int sofar;
+  int ret;
+
+  logC("\n");
+
+  for(i=0,sofar=0;sofar<len;i++){
+    int toread = (i==0?1:len-sofar);
+    int ret;
+    /* first read should also trigger a short seek; one sector so seek duration dominates */
+    if((ret=cdda_read(d,NULL,lba+sofar,toread))<=0){
+      /* media error! grr!  retry elsewhere */
+      if(ret==-404)return -404;
+      return -1;
+    }
+
+    x = cdda_milliseconds(d);
+    if(x>9999)x=9999;
+    if(x<0)x=0;
+    logC("%d:%d ",ret,x);
+    
+    latency[i]=x;
+    sectors[i]=ret;
+    sofar+=ret;
+    if(i){
+      sum+=x;
+      sumsq+= x*x /(float)ret;
+    }
+  }
+  
+  /* we count even the upper outliers because the drive is almost
+     certainly reading ahead and that will work itself out as we keep
+     reading to catch up.  Besides-- the tests would rather see too
+     slow a timing than too fast; the timing data is used as an
+     optimization when sleeping. */
+  {
+    double mean = sum/(float)(len-1);
+    double stddev = sqrt( (sumsq/(float)(len-1) - mean*mean));
+    
+    printC("%4dms seek, %.2fms/sec read [%.1fx]",latency[0],mean,1000./75./mean);
+    logC("\n\tInitial seek latency (%d sectors): %dms",len,latency[0]);
+    logC("\n\tAverage read latency: %.2fms/sector (raw speed: %.1fx)",mean,1000./75./mean);
+    logC("\n\tRead latency standard deviation: %.2fms/sector",stddev);
+    
+    return sum;
+  }
+}
+
+static float retime_drive(cdrom_drive *d, FILE *progress, FILE *log, int lba, int readahead, float oldmean){
+  int sectors = 2000;
+  int total;
+  float newmean;
+  if(sectors*oldmean > 5000) sectors=5000/oldmean;
+  readahead*=10;
+  readahead/=9;
+  if(readahead>sectors)sectors=readahead;
+
+  printC("\bo");
+  logC("\n\tRetiming drive...                               ");
+  
+  total = time_drive(d,NULL,log,lba,sectors);
+  newmean = total/(float)sectors;
+
+  logC("\n\tOld mean=%.2fms/sec, New mean=%.2fms/sec\n",oldmean,newmean);
+  printC("\b");
+
+  if(newmean>oldmean)return newmean;
+  return oldmean;
+}
+
+int analyze_cache(cdrom_drive *d, FILE *progress, FILE *log, int speed){
+
+  /* Some assumptions about timing: 
+
+     We can't perform cache determination timing based on looking at
+     average transfer times; on slow setups, the speed of a drive
+     reading sectors via PIO will not be reliably distinguishable from
+     the same drive returning data from the cache via pio.  We need
+     something even more noticable and reliable: the seek time. It is
+     unlikely we'd ever see a seek latency of under ~10ms given the
+     synchronization requirements of a CD and the maximum possible
+     rotational velocity. A cache hit would always be faster, even
+     with PIO.
+
+     Further complicating things, we have to watch the data collection
+     carefully as we're not always going to be on an unloaded system,
+     and we even have to guard against other apps accessing the drive
+     (something that should never happen on purpose, but could happen
+     by accident).  As we know in our testing when seeks should never
+     occur, a sudden seek-sized latency popping up in the middle of a
+     collection is an indication that collection is possibly invalid.
+
+     A second cause of 'spurious latency' would be media damage; if
+     we're consistently hitting latency on the same sector during
+     initial collection, may need to move past it. */
+
+  int i,j,ret;
+  int firstsector=-1;
+  int lastsector=-1;
+  int firsttest=-1;
+  int lasttest=-1;
+  int max_retries=20;
+  float median;
+  int offset;
+  int warn=0;
+  int current=1000;
+  int hi=15000;
+  int cachesize;
+  int readahead;
+  int rollbehind;
+  int cachegran;
+  float mspersector;
+  if(speed<=0)speed=-1;
+
+  reportC("\n=================== Checking drive cache/timing behavior ===================\n");
+  d->error_retry=0;
+
+  /* verify the lib and cache analysis match */
+  if(strcmp(VERSIONNUM,paranoia_version())){
+    reportC("\nWARNING: cdparanoia application (and thus the cache tests) does not match the"
+	    "\ninstalled (or in use) libcdda_paranoia.so library.  The final verdict of this"
+	    "\ntesting may or may not be accurate for the actual version of the paranoia"
+	    "library.  Continuing anyway...\n\n");
+  }
+
+  /* find the longest stretch of available audio data */
+
+  for(i=0;i<d->tracks;i++){
+    if(cdda_track_audiop(d,i+1)==1){
+      if(firsttest == -1)
+	firsttest=cdda_track_firstsector(d,i+1);
+      lasttest=cdda_track_lastsector(d,i+1);
+      if(lasttest-firsttest > lastsector-firstsector){
+	firstsector=firsttest;
+	lastsector=lasttest;
+      }
+    }else{
+      firsttest=-1;
+      lasttest=-1;
+    }
+  }
+
+  if(firstsector==-1){
+    reportC("\n\tNo audio on disc; Cannot determine timing behavior...");
+    return -1;
+  }
+
+  /* Dump some initial timing data to give a little context for human
+     eyes.  Take readings ten minutes apart (45000 sectors) and at end of disk. */
+  {
+    int best=0;
+    int bestcount=0;
+    int iterating=0;
+
+    offset = lastsector-firstsector-current-1;
+
+    reportC("\nSeek/read timing:\n");
+
+    while(offset>=firstsector){
+      int m = offset/4500;
+      int s = (offset-m*4500)/75;
+      int f = offset-m*4500-s*75;
+      int sofar;
+
+      if(iterating){
+	reportC("\n");
+      }else{
+	printC("\r");
+	logC("\n");
+      }
+      reportC("\t[%02d:%02d.%02d]: ",m,s,f);
+
+      /* initial seek to put at at a small offset past end of upcoming reads */
+      if((ret=cdda_read(d,NULL,offset+current+1,1))<0){
+	/* media error! grr!  retry elsewhere */
+	if(ret==-404)return -1;
+	reportC("\n\tWARNING: media error during read; continuing at next offset...");
+	offset = (offset-firstsector+44999)/45000*45000+firstsector;
+	offset-=45000;
+	continue;
+      }
+  
+      sofar=time_drive(d,progress, log, offset, current);
+      if(offset==firstsector)mspersector = sofar/(float)current;
+      if(sofar==-404)
+	return -1;
+      else if(sofar<0){
+	reportC("\n\tWARNING: media error during read; continuing at next offset...");
+	offset = (offset-firstsector+44999)/45000*45000+firstsector;
+	offset-=45000;
+	continue;
+      }else{
+	if(!iterating){
+	  if(best==0 || sofar*1.01<best){
+	    best= sofar;
+	    bestcount=0;
+	  }else{
+	    bestcount+=sofar;
+	    if(bestcount>sofar && bestcount>4000)
+	      iterating=1;
+	  }
+	}
+      }
+    next:
+
+      if(iterating){
+	offset = (offset-firstsector+44999)/45000*45000+firstsector;
+	offset-=45000;
+	printC("                 ");
+      }else{
+	offset--;
+	printC(" spinning up...  ");
+      }
+    }
+  }
+
+  reportC("\n\nAnalyzing readahead cache access...\n");
+  
+  /* search on cache size; cache hits are fast, seeks are not, so a
+     linear search through cache hits up to a miss are faster than a
+     bisection */
+  {
+    int under=1;
+    int onex=0;
+    current=0;
+    offset = firstsector+10;
+    
+    while(current <= hi && under){
+      int i,j;
+      under=0;
+      current++;
+      
+      if(onex){
+	if(speed==-1){
+	  logC("\tAttempting to reset read speed to full... ");
+	}else{
+	  logC("\tAttempting to reset read speed to %dx... ",speed);
+	}
+	if(cdda_speed_set(d,speed)){
+	  logC("failed.\n");
+	}else{
+	  logC("drive said OK\n");
+	}
+	onex=0;
+      }
+
+      printC("\r");
+      reportC("\tFast search for approximate cache size... %d sectors            ",current-1);
+      logC("\n");
+      
+      for(i=0;i<15 && !under;i++){
+	for(j=0;;j++){
+	  int ret1,ret2;
+	  if(i>=5){
+	    int sofar=0;
+	    
+	    if(i==5){
+	      printC("\r");
+	      reportC("\tSlow verify for approximate cache size... %d sectors",current-1);
+	      logC("\n");
+	      
+	      logC("\tAttempting to reduce read speed to 1x... ");
+	      if(cdda_speed_set(d,1)){
+		logC("failed.\n");
+	      }else{
+		logC("drive said OK\n");
+	      }
+	      onex=1;
+	    }
+	    printC(".");
+	    logC("\t\t>>> ");
+	    
+	    while(sofar<current){
+	      ret1 = cdda_read(d,NULL,offset+sofar,current-sofar);
+	      logC("slow_read=%d:%d ",ret1,cdda_milliseconds(d));
+	      if(ret1<=0)break;
+	      sofar+=ret1;
+	    }
+	  }else{
+	    ret1 = cdda_read(d,NULL,offset+current-1,1);
+	    logC("\t\t>>> fast_read=%d:%d ",ret1,cdda_milliseconds(d));
+	  }
+	  ret2 = cdda_read(d,NULL,offset,1);
+	  logC("seek_read=%d:%d\n",ret2,cdda_milliseconds(d));
+	  
+	  if(ret1<=0 || ret2<=0){
+	    offset+=current+100;
+	    if(j==10 || offset+current>lastsector){
+	      reportC("\n\tToo many read errors while performing drive cache checks;"
+		      "\n\t  aborting test.\n\n");
+	      return(-1);
+	    }
+	    reportC("\n\tRead error while performing drive cache checks;"
+		    "\n\t  choosing new offset and trying again.\n");
+	  }else{
+	    if(cdda_milliseconds(d)==-1){
+	      reportC("\n\tTiming error while performing drive cache checks; aborting test.\n");
+	      return(-1);
+	    }else{
+	      if(cdda_milliseconds(d)<9){
+		under=1;
+	      }
+	      break;
+	    }
+	  }
+	}
+      }
+    } 
+  }
+  cachesize=current-1;
+
+  printC("\r");
+  if(cachesize==hi){
+    reportC("\tWARNING: Cannot determine drive cache size or behavior!          \n");
+    return 1;
+  }else if(cachesize){
+    reportC("\tApproximate random access cache size: %d sector(s)               \n",cachesize);
+  }else{
+    reportC("\tDrive does not cache nonlinear access                            \n");
+    return 0;
+  }
+  
+  if(speed==-1){
+    logC("\tAttempting to reset read speed to full... ");
+  }else{
+    logC("\tAttempting to reset read speed to %d... ",speed);
+  }
+  if(cdda_speed_set(d,speed)){
+    logC("failed.\n");
+  }else{
+    logC("drive said OK\n");
+  }
+
+  /* The readahead cache size ascertained above is likely qualified by
+     background 'rollahead'; that is, the drive's readahead process is
+     often working ahead of our actual linear reads, and if reads stop
+     or are interrupted, readahead continues and overflows the cache.
+     It is also the case that the cache size we determined above is
+     slightly too low because readahead is probably always working
+     ahead of reads. 
+
+     Determine the rollahead size a few ways (which may disagree:
+     1) Read number of sectors equal to cache size; pause; read backward until seek
+     2) Read sectors equal to cache-rollahead; verify reading back to beginning does not seek 
+     3) Read sectors equal to cache; pause; read ahead until seek delay
+  */
+
+  {
+    int lower=0;
+    int gran=64;
+    int it=2;
+    int tests=0;
+    int under=1;
+    readahead=0;
+    
+    while(gran>1 || under){
+      tests++;
+      if(tests>8 && gran<64){
+	gran<<=3;
+	tests=0;
+	it=2;
+      }
+      if(gran && !under){
+	gran>>=3;
+	tests=0;
+	if(gran==1)it=10;
+      }
+
+      under=0;
+      readahead=lower+gran;
+
+      printC("\r");
+      logC("\n");
+      reportC("\tTesting background readahead past read cursor... %d",readahead);
+      printC("           \b\b\b\b\b\b\b\b\b\b\b");
+      for(i=0;i<it;i++){
+	int sofar=0,ret,retry=0;
+	logC("\n\t\t%d >>> ",i);
+
+	while(sofar<cachesize){
+	  ret = cdda_read(d,NULL,offset+sofar,cachesize-sofar);
+	  if(ret<=0)goto error;
+	  logC("%d:%d ",ret,cdda_milliseconds(d));
+
+	  /* some drives can lose sync and perform an internal resync,
+	     which can also cause readahead to restart.  If we see
+	     seek-like delays during the initial cahe load, retry the
+	     preload */
+
+	  sofar+=ret;
+	}
+	
+	printC(".");
+
+	/* what we'd predict is needed to let the readahead process work. */
+	{
+	  int usec=mspersector*(readahead)*(4+i)*500;
+	  int max= 13000*2*readahead; /* corresponds to .5x */
+	  if(usec>max)usec=max;
+	  logC("sleep=%dus ",usec);
+	  usleep(usec);
+	}
+	
+	/* seek to offset+cachesize+readahead */
+	ret = cdda_read(d,NULL,offset+cachesize+readahead-1,1);
+	if(ret<=0)break;
+	logC("ahead=%d:%d",readahead,cdda_milliseconds(d));
+	if(cdda_milliseconds(d)<9){
+	  under=1;
+	  break;
+	}else if(i&1){
+	  /* retime the drive just to be conservative */
+	  mspersector=retime_drive(d, progress, log, offset, readahead, mspersector);
+	}
+      }
+      
+      if(under)
+	lower=readahead;
+
+    }
+    readahead=lower;
+  }
+  logC("\n");
+  printC("\r");
+  if(readahead==0){
+    reportC("\tDrive does not read ahead past read cursor (very strange)     \n");
+  }else{
+    reportC("\tDrive readahead past read cursor: %d sector(s)                \n",readahead);
+  }
+  
+  reportC("\tTesting cache tail cursor...");
+
+  while(1){
+    rollbehind=cachesize;
+    
+    for(i=0;i<10 && rollbehind;i++){
+      int sofar=0,ret,retry=0;
+      logC("\n\t\t>>> ");
+      printC(".");
+      while(sofar<cachesize){
+	ret = cdda_read(d,NULL,offset+sofar,cachesize-sofar);
+	if(ret<=0)goto error;
+	logC("%d:%d ",ret,cdda_milliseconds(d));
+	sofar+=ret;
+      }
+    
+      /* Pause what we'd predict is needed to let the readahead process work. */
+      {
+	int usec=mspersector*readahead*5000;
+	logC("\n\t\tsleeping %d microseconds",usec);
+	usleep(usec);
+      }
+      
+      /* read backwards until we seek */
+      logC("\n\t\t<<< ");
+      sofar=rollbehind;
+      while(sofar>0){
+	sofar--;
+	ret = cdda_read(d,NULL,offset+sofar,1);
+	if(ret<=0)break;
+	logC("%d:%d ",sofar,cdda_milliseconds(d));
+	if(cdda_milliseconds(d)>8){
+	  rollbehind=sofar+1;
+	  break;
+	}
+	rollbehind=sofar;
+      }
+    error:
+      if(ret<=0){
+	offset+=cachesize;
+	retry++;
+	if(retry>10 || offset+cachesize>lastsector){
+	  reportC("\n\tToo many read errors while performing drive cache checks;"
+		  "\n\t  aborting test.\n\n");
+	  return(-1);
+	}
+	reportC("\n\tRead error while performing drive cache checks;"
+		"\n\t  choosing new offset and trying again.\n");
+	continue;
+      }
+    }
+
+    /* verify that the drive timing didn't suddenly change */
+    {
+      float newms=retime_drive(d, progress, log, offset, readahead, mspersector);
+      if(newms > mspersector*1.2){
+	mspersector=newms;
+	printC("\r");
+	reportC("\tDrive timing changed during test; retrying...");
+	continue;
+      }
+    }
+    break;
+
+  }
+  
+  logC("\n");
+  printC("\r");
+  if(rollbehind==0){
+    reportC("\tCache tail cursor tied to read cursor                      \n");
+  }else{
+    reportC("\tCache tail rollbehind: %d sector(s)                        \n",rollbehind);
+  }
+  
+  reportC("\tTesting granularity of cache tail");
+
+  while(1){
+    cachegran=cachesize+1;
+    for(i=0;i<10 && cachegran;i++){
+      int sofar=0,ret,retry=0;
+      logC("\n\t\t>>> ");
+      printC(".");
+      while(sofar<cachesize+1){
+	ret = cdda_read(d,NULL,offset+sofar,cachesize-sofar+1);
+	if(ret<=0)goto error2;
+	logC("%d:%d ",ret,cdda_milliseconds(d));
+	sofar+=ret;
+      }
+      
+      /* Pause what we'd predict is needed to let the readahead process work. */
+      {
+	int usec=mspersector*readahead*5000;
+	logC("\n\t\tsleeping %d microseconds",usec);
+	usleep(usec);
+      }
+      
+      /* read backwards until we seek */
+      logC("\n\t\t<<< ");
+      sofar=cachegran;
+      while(sofar){
+	sofar--;
+	ret = cdda_read(d,NULL,offset+sofar,1);
+	if(ret<=0)break;
+	logC("%d:%d ",sofar,cdda_milliseconds(d));
+	if(cdda_milliseconds(d)>8){
+	  cachegran=sofar+1;
+	  break;
+	}
+	cachegran=sofar;
+      }
+    error2:
+      if(ret<=0){
+	offset+=cachesize;
+	retry++;
+	if(retry>10 || offset+cachesize>lastsector){
+	  reportC("\n\tToo many read errors while performing drive cache checks;"
+		  "\n\t  aborting test.\n\n");
+	  return(-1);
+	}
+	reportC("\n\tRead error while performing drive cache checks;"
+		"\n\t  choosing new offset and trying again.\n");
+	continue;
+      }
+    }
+
+    /* verify that the drive timing didn't suddenly change */
+    {
+      float newms=retime_drive(d, progress, log, offset, readahead, mspersector);
+      if(newms > mspersector*1.2){
+	mspersector=newms;
+	printC("\r");
+	reportC("\tDrive timing changed during test; retrying...");
+	continue;
+      }
+    }
+    break;
+    
+  }
+  
+  cachegran -= rollbehind;
+
+  logC("\n");
+  printC("\r");
+  reportC("\tCache tail granularity: %d sector(s)                      \n",cachegran);
+
+
+  /* This is similar to the Fast search above, but just in case the
+     cache is being tracked as multiple areas that are treated
+     differently if non-contiguous.... */
+  {
+    int seekoff = cachesize*3;
+    int under=0;
+    reportC("\nVerifying that readahead cache is contiguous...\n");
+    printC("\ttesting");
+  
+    for(i=0;i<30 && !under;i++){
+      printC(".");
+      for(j=0;;j++){
+	int ret1,ret2;
+
+	if(offset+seekoff>lastsector){
+	  reportC("\n\tOut of readable space on CDROM while performing drive checks;"
+		  "\n\t  aborting test.\n\n");
+	  return(-1);
+	}
+	
+
+	ret1 = cdda_read(d,NULL,offset+seekoff,1);
+	logC("\t\t>>> %d:%d ",offset+seekoff,cdda_milliseconds(d));
+	ret2 = cdda_read(d,NULL,offset,1);
+	logC("seek_read:%d\n",cdda_milliseconds(d));
+	
+	if(ret1<=0 || ret2<=0){
+	  offset+=cachesize+100;
+	  if(j==10){
+	    reportC("\n\tToo many read errors while performing drive cache checks;"
+		    "\n\t  aborting test.\n\n");
+	    return(-1);
+	  }
+	  reportC("\n\tRead error while performing drive cache checks;"
+		  "\n\t  choosing new offset and trying again.\n");
+	}else{
+	  if(cdda_milliseconds(d)==-1){
+	    reportC("\n\tTiming error while performing drive cache checks; aborting test.\n");
+	    return(-1);
+	  }else{
+	    if(cdda_milliseconds(d)<9)under=1;
+	    break;
+	  }
+	}
+      }
+    }
+    printC("\r");
+    if(under){
+      reportC("WARNING: Drive cache does not appear to be contiguous!\n");
+      warn=1;
+    }else{
+      reportC("\tDrive cache tests as contiguous.                \n");
+    }
+  }
+
+  /* Verify that a read that begins before the cached readahead dumps
+     the entire readahead cache */
+
+  /* This is tricky because we can't simply read a one sector
+     back seek, then rely on timing/seeking of subsequent sectors; the
+     drive may well not seek ahead if reading linearly would be faster
+     (and it often will be), and simply reading haead after the seek
+     and watching timing will be inaccurate because the drive may roll
+     some readahead into the initial seek before returning the first
+     block. */
+
+  /* we will need to use the timing of reading from media in one form
+     or another and thus need to guard against slow bus transfer times
+     [eg, no DMA] swamping the actual read time from media. */
+
+  /* sample cache access for ten realtime seconds. */
+  //{
+    //int cachems;
+
+    //reportC("\nVerifying that seeking before cache dumps readahead...");
+    //reportC("\n\tSampling cache timing... ");
+  //}
+
+
+  /* Check to see that cdda_clear_cache clears the specified cache area */
+
+  /* Does cdda_clear_cache result in noncontiguous cache areas? */
+
+
+
+  /* does the readahead cache exceed the maximum Paranoia currently expects? */
+  {
+    cdrom_paranoia *p=paranoia_init(d);
+    if(cachesize > paranoia_cachemodel_size(p,-1)){
+      reportC("\nWARNING: This drive appears to be caching more sectors of\n"
+	      "           readahead than Paranoia can currently handle!\n");
+      warn=1;
+      
+    }
+    paranoia_free(p);
+  }
+
+
+  return warn;
+}
+
+

Modified: trunk/cdparanoia/interface/cdda_interface.h
===================================================================
--- trunk/cdparanoia/interface/cdda_interface.h	2008-09-04 18:22:46 UTC (rev 15259)
+++ trunk/cdparanoia/interface/cdda_interface.h	2008-09-04 19:02:47 UTC (rev 15260)
@@ -123,7 +123,6 @@
 
 extern char *cdda_version();
 extern int cdda_speed_set(cdrom_drive *d, int speed);
-extern int cdda_speed_get(cdrom_drive *d);
 extern void cdda_verbose_set(cdrom_drive *d,int err_action, int mes_action);
 extern char *cdda_messages(cdrom_drive *d);
 extern char *cdda_errors(cdrom_drive *d);

Modified: trunk/cdparanoia/interface/interface.c
===================================================================
--- trunk/cdparanoia/interface/interface.c	2008-09-04 18:22:46 UTC (rev 15259)
+++ trunk/cdparanoia/interface/interface.c	2008-09-04 19:02:47 UTC (rev 15260)
@@ -101,21 +101,12 @@
 int cdda_speed_set(cdrom_drive *d, int speed)
 {
   if(d->set_speed)
-    if(!d->set_speed(d,speed)){
-      d->private->speed=speed;
-      return 0;
-    }
-      
+    if(!d->set_speed(d,speed))return 0;
+  
   cderror(d,"405: Option not supported by drive\n");
   return -405;
 }
 
-/* -1 is 'full speed', 0 is 'unknown' */
-int cdda_speed_get(cdrom_drive *d)
-{
-  return d->private->speed;
-}
-
 long cdda_read(cdrom_drive *d, void *buffer, long beginsector, long sectors){
   if(d->opened){
     if(sectors>0){

Modified: trunk/cdparanoia/interface/low_interface.h
===================================================================
--- trunk/cdparanoia/interface/low_interface.h	2008-09-04 18:22:46 UTC (rev 15259)
+++ trunk/cdparanoia/interface/low_interface.h	2008-09-04 19:02:47 UTC (rev 15260)
@@ -102,7 +102,6 @@
   unsigned char *sg_buffer; /* points into sg_hd */
   clockid_t clock;
   int last_milliseconds;
-  int speed;
 
   int  (*cache_clear)  (struct cdrom_drive *d, int lba, int sectors);
 };

Modified: trunk/cdparanoia/main.c
===================================================================
--- trunk/cdparanoia/main.c	2008-09-04 18:22:46 UTC (rev 15259)
+++ trunk/cdparanoia/main.c	2008-09-04 19:02:47 UTC (rev 15260)
@@ -38,6 +38,8 @@
 #include "version.h"
 #include "header.h"
 
+extern int analyze_cache(cdrom_drive *d, FILE *progress, FILE *log, int speed);
+
 static long parse_offset(cdrom_drive *d, char *offset, int begin){
   long track=-1;
   long hours=-1;
@@ -1038,7 +1040,7 @@
   }
   
   if(run_cache_test){
-    int warn=paranoia_analyze_verify(d, stderr, reportfile);
+    int warn=analyze_cache(d, stderr, reportfile, force_cdrom_speed);
     
     if(warn==0){
       reportC("\nDrive tests OK with Paranoia.\n\n");

Modified: trunk/cdparanoia/paranoia/Makefile.in
===================================================================
--- trunk/cdparanoia/paranoia/Makefile.in	2008-09-04 18:22:46 UTC (rev 15259)
+++ trunk/cdparanoia/paranoia/Makefile.in	2008-09-04 19:02:47 UTC (rev 15260)
@@ -18,7 +18,7 @@
 RANLIB=@RANLIB@
 CPPFLAGS+=-D_REENTRANT
 
-OFILES = paranoia.o p_block.o overlap.o gap.o isort.o cachetest.o
+OFILES = paranoia.o p_block.o overlap.o gap.o isort.o 
 #TFILES = isort.t gap.t p_block.t paranoia.t
 
 LIBS = ../interface/libcdda_interface.a -lm

Deleted: trunk/cdparanoia/paranoia/cachetest.c
===================================================================
--- trunk/cdparanoia/paranoia/cachetest.c	2008-09-04 18:22:46 UTC (rev 15259)
+++ trunk/cdparanoia/paranoia/cachetest.c	2008-09-04 19:02:47 UTC (rev 15260)
@@ -1,702 +0,0 @@
-/*
- * GNU Lesser General Public License 2.1 applies
- * Copyright (C) 2008 Monty <monty at xiph.org>
- *
- */
-
-/* this is in the paranoia library because the analysis is matched to
-   cache modelling of a specific library version, not matched to the
-   specific application (eg, cdparanoia version, which is simply a
-   wrapper around the libs) */
-
-/* we can ask most drives what their various caches' sizes are, but no
-   drive will tell if it caches redbook data.  None should, many do,
-   and there's no way in (eg) MMC/ATAPI to tell a cdrom drive not to
-   cache when accessing audio.  SCSI drives have a FUA facility, but
-   it's not clear how many ignore it.  MMC does specify some cache
-   side effect as part of SET READ AHEAD, but it's not clear we can
-   rely on them.  For that reason, we need to empirically determine
-   cache size and strategy used for reads. */
-
-#include <string.h>
-#include <stdio.h>
-#include <math.h>
-#include "../interface/cdda_interface.h"
-#include "p_block.h"
-
-#define reportC(...) {if(progress){fprintf(progress, __VA_ARGS__);}	\
-    if(log){fprintf(log, __VA_ARGS__);}}
-#define printC(...) {if(progress){fprintf(progress, __VA_ARGS__);}}
-#define logC(...) {if(log){fprintf(log, __VA_ARGS__);}}
-
-static int time_drive(cdrom_drive *d, FILE *progress, FILE *log, int lba, int len){
-  int i,j,x;
-  int latency[len];
-  int sectors[len];
-  double sum=0;
-  double sumsq=0;
-  int sofar;
-  int ret;
-
-  logC("\n");
-  
-  for(i=0,sofar=0;sofar<len;i++){
-    int toread = (i==0?1:len-sofar);
-    int ret;
-    /* first read should also trigger a short seek; one sector so seek duration dominates */
-    if((ret=cdda_read(d,NULL,lba+sofar,toread))<=0){
-      /* media error! grr!  retry elsewhere */
-      if(ret==-404)return -404;
-      return -1;
-    }
-
-    x = cdda_milliseconds(d);
-    if(x>9999)x=9999;
-    if(x<0)x=0;
-    logC("%d:%d ",ret,x);
-    
-    latency[i]=x;
-    sectors[i]=ret;
-    sofar+=ret;
-    if(i){
-      sum+=x;
-      sumsq+= x*x /(float)ret;
-    }
-  }
-  
-  /* we count even the upper outliers because the drive is almost
-     certainly reading ahead and that will work itself out as we keep
-     reading to catch up.  Besides-- the tests would rather see too
-     slow a timing than too fast; the timing data is used as an
-     optimization when sleeping. */
-  {
-    double mean = sum/(float)(len-1);
-    double stddev = sqrt( (sumsq/(float)(len-1) - mean*mean));
-    
-    printC("%4dms seek, %.2fms/sec read [%.1fx]",latency[0],mean,1000./75./mean);
-    logC("\n\tInitial seek latency (%d sectors): %dms",len,latency[0]);
-    logC("\n\tAverage read latency: %.2fms/sector (raw speed: %.1fx)",mean,1000./75./mean);
-    logC("\n\tRead latency standard deviation: %.2fms/sector",stddev);
-    
-    return sum;
-  }
-}
-
-static float retime_drive(cdrom_drive *d, FILE *progress, FILE *log, int lba, int readahead, float oldmean){
-  int sectors = 2000;
-  int total;
-  float newmean;
-  if(sectors*oldmean > 5000) sectors=5000/oldmean;
-  readahead*=10;
-  readahead/=9;
-  if(readahead>sectors)sectors=readahead;
-
-  printC("\bo");
-  logC("\n\tRetiming drive...                               ");
-  
-  total = time_drive(d,NULL,log,lba,sectors);
-  newmean = total/(float)sectors;
-
-  logC("\n\tOld mean=%.2fms/sec, New mean=%.2fms/sec\n",oldmean,newmean);
-  printC("\b");
-
-  if(newmean>oldmean)return newmean;
-  return oldmean;
-}
-
-int paranoia_analyze_verify(cdrom_drive *d, FILE *progress, FILE *log){
-
-  /* Some assumptions about timing: 
-
-     We can't perform cache determination timing based on looking at
-     average transfer times; on slow setups, the speed of a drive
-     reading sectors via PIO will not be reliably distinguishable from
-     the same drive returning data from the cache via pio.  We need
-     something even more noticable and reliable: the seek time. It is
-     unlikely we'd ever see a seek latency of under ~10ms given the
-     synchronization requirements of a CD and the maximum possible
-     rotational velocity. A cache hit would always be faster, even
-     with PIO.
-
-     Further complicating things, we have to watch the data collection
-     carefully as we're not always going to be on an unloaded system,
-     and we even have to guard against other apps accessing the drive
-     (something that should never happen on purpose, but could happen
-     by accident).  As we know in our testing when seeks should never
-     occur, a sudden seek-sized latency popping up in the middle of a
-     collection is an indication that collection is possibly invalid.
-
-     A second cause of 'spurious latency' would be media damage; if
-     we're consistently hitting latency on the same sector during
-     initial collection, may need to move past it. */
-
-  int i,j,ret;
-  int firstsector=-1;
-  int lastsector=-1;
-  int firsttest=-1;
-  int lasttest=-1;
-  int max_retries=20;
-  float median;
-  int offset;
-  int warn=0;
-  int current=1000;
-  int hi=15000;
-  int cachesize;
-  int readahead;
-  int rollbehind;
-  int cachegran;
-  int speed = cdda_speed_get(d);
-  float mspersector;
-  if(speed<=0)speed=-1;
-
-  reportC("\n=================== Checking drive cache/timing behavior ===================\n");
-  d->error_retry=0;
-
-  /* find the longest stretch of available audio data */
-
-  for(i=0;i<d->tracks;i++){
-    if(cdda_track_audiop(d,i+1)==1){
-      if(firsttest == -1)
-	firsttest=cdda_track_firstsector(d,i+1);
-      lasttest=cdda_track_lastsector(d,i+1);
-      if(lasttest-firsttest > lastsector-firstsector){
-	firstsector=firsttest;
-	lastsector=lasttest;
-      }
-    }else{
-      firsttest=-1;
-      lasttest=-1;
-    }
-  }
-
-  if(firstsector==-1){
-    reportC("\n\tNo audio on disc; Cannot determine timing behavior...");
-    return -1;
-  }
-
-  /* Dump some initial timing data to give a little context for human
-     eyes.  Take readings ten minutes apart (45000 sectors) and at end of disk. */
-  {
-    int best=0;
-    int bestcount=0;
-    int iterating=0;
-
-    offset = lastsector-firstsector-current-1;
-
-    reportC("\nSeek/read timing:\n");
-
-    while(offset>=firstsector){
-      int m = offset/4500;
-      int s = (offset-m*4500)/75;
-      int f = offset-m*4500-s*75;
-      int sofar;
-
-      if(iterating){
-	reportC("\n");
-      }else{
-	printC("\r");
-	logC("\n");
-      }
-      reportC("\t[%02d:%02d.%02d]: ",m,s,f);
-
-      /* initial seek to put at at a small offset past end of upcoming reads */
-      if((ret=cdda_read(d,NULL,offset+current+1,1))<0){
-	/* media error! grr!  retry elsewhere */
-	if(ret==-404)return -1;
-	reportC("\n\tWARNING: media error during read; continuing at next offset...");
-	offset = (offset-firstsector+44999)/45000*45000+firstsector;
-	offset-=45000;
-	continue;
-      }
-  
-      sofar=time_drive(d,progress, log, offset, current);
-      if(offset==firstsector)mspersector = sofar/(float)current;
-      if(sofar==-404)
-	return -1;
-      else if(sofar<0){
-	reportC("\n\tWARNING: media error during read; continuing at next offset...");
-	offset = (offset-firstsector+44999)/45000*45000+firstsector;
-	offset-=45000;
-	continue;
-      }else{
-	if(!iterating){
-	  if(best==0 || sofar*1.01<best){
-	    best= sofar;
-	    bestcount=0;
-	  }else{
-	    bestcount+=sofar;
-	    if(bestcount>sofar && bestcount>4000)
-	      iterating=1;
-	  }
-	}
-      }
-    next:
-
-      if(iterating){
-	offset = (offset-firstsector+44999)/45000*45000+firstsector;
-	offset-=45000;
-	printC("                 ");
-      }else{
-	offset--;
-	printC(" spinning up...  ");
-      }
-    }
-  }
-
-  reportC("\n\nAnalyzing readahead cache access...\n");
-  
-  /* search on cache size; cache hits are fast, seeks are not, so a
-     linear search through cache hits up to a miss are faster than a
-     bisection */
-  {
-    int under=1;
-    int onex=0;
-    current=0;
-    offset = firstsector+10;
-    
-    while(current <= hi && under){
-      int i,j;
-      under=0;
-      current++;
-      
-      if(onex){
-	if(speed==-1){
-	  logC("\tAttempting to reset read speed to full... ");
-	}else{
-	  logC("\tAttempting to reset read speed to %dx... ",speed);
-	}
-	if(cdda_speed_set(d,speed)){
-	  logC("failed.\n");
-	}else{
-	  logC("drive said OK\n");
-	}
-	onex=0;
-      }
-
-      printC("\r");
-      reportC("\tFast search for approximate cache size... %d sectors            ",current-1);
-      logC("\n");
-      
-      for(i=0;i<15 && !under;i++){
-	for(j=0;;j++){
-	  int ret1,ret2;
-	  if(i>=5){
-	    int sofar=0;
-	    
-	    if(i==5){
-	      printC("\r");
-	      reportC("\tSlow verify for approximate cache size... %d sectors",current-1);
-	      logC("\n");
-	      
-	      logC("\tAttempting to reduce read speed to 1x... ");
-	      if(cdda_speed_set(d,1)){
-		logC("failed.\n");
-	      }else{
-		logC("drive said OK\n");
-	      }
-	      onex=1;
-	    }
-	    printC(".");
-	    logC("\t\t>>> ");
-	    
-	    while(sofar<current){
-	      ret1 = cdda_read(d,NULL,offset+sofar,current-sofar);
-	      logC("slow_read=%d:%d ",ret1,cdda_milliseconds(d));
-	      if(ret1<=0)break;
-	      sofar+=ret1;
-	    }
-	  }else{
-	    ret1 = cdda_read(d,NULL,offset+current-1,1);
-	    logC("\t\t>>> fast_read=%d:%d ",ret1,cdda_milliseconds(d));
-	  }
-	  ret2 = cdda_read(d,NULL,offset,1);
-	  logC("seek_read=%d:%d\n",ret2,cdda_milliseconds(d));
-	  
-	  if(ret1<=0 || ret2<=0){
-	    offset+=current+100;
-	    if(j==10 || offset+current>lastsector){
-	      reportC("\n\tToo many read errors while performing drive cache checks;"
-		      "\n\t  aborting test.\n\n");
-	      return(-1);
-	    }
-	    reportC("\n\tRead error while performing drive cache checks;"
-		    "\n\t  choosing new offset and trying again.\n");
-	  }else{
-	    if(cdda_milliseconds(d)==-1){
-	      reportC("\n\tTiming error while performing drive cache checks; aborting test.\n");
-	      return(-1);
-	    }else{
-	      if(cdda_milliseconds(d)<9){
-		under=1;
-	      }
-	      break;
-	    }
-	  }
-	}
-      }
-    } 
-  }
-  cachesize=current-1;
-
-  printC("\r");
-  if(cachesize==hi){
-    reportC("\tWARNING: Cannot determine drive cache size or behavior!          \n");
-    return 1;
-  }else if(cachesize){
-    reportC("\tApproximate random access cache size: %d sector(s)               \n",cachesize);
-  }else{
-    reportC("\tDrive does not cache nonlinear access                            \n");
-    return 0;
-  }
-  
-  if(speed==-1){
-    logC("\tAttempting to reset read speed to full... ");
-  }else{
-    logC("\tAttempting to reset read speed to %d... ",speed);
-  }
-  if(cdda_speed_set(d,speed)){
-    logC("failed.\n");
-  }else{
-    logC("drive said OK\n");
-  }
-
-  /* The readahead cache size ascertained above is likely qualified by
-     background 'rollahead'; that is, the drive's readahead process is
-     often working ahead of our actual linear reads, and if reads stop
-     or are interrupted, readahead continues and overflows the cache.
-     It is also the case that the cache size we determined above is
-     slightly too low because readahead is probably always working
-     ahead of reads. 
-
-     Determine the rollahead size a few ways (which may disagree:
-     1) Read number of sectors equal to cache size; pause; read backward until seek
-     2) Read sectors equal to cache-rollahead; verify reading back to beginning does not seek 
-     3) Read sectors equal to cache; pause; read ahead until seek delay
-  */
-
-  {
-    int lower=0;
-    int gran=64;
-    int it=2;
-    int tests=0;
-    int under=1;
-    readahead=0;
-    
-    while(gran>1 || under){
-      tests++;
-      if(tests>8 && gran<64){
-	gran<<=3;
-	tests=0;
-	it=2;
-      }
-      if(gran && !under){
-	gran>>=3;
-	tests=0;
-	if(gran==1)it=10;
-      }
-
-      under=0;
-      readahead=lower+gran;
-
-      printC("\r");
-      logC("\n");
-      reportC("\tTesting background readahead past read cursor... %d",readahead);
-      printC("           \b\b\b\b\b\b\b\b\b\b\b");
-      for(i=0;i<it;i++){
-	int sofar=0,ret,retry=0;
-	logC("\n\t\t%d >>> ",i);
-
-	while(sofar<cachesize){
-	  ret = cdda_read(d,NULL,offset+sofar,cachesize-sofar);
-	  if(ret<=0)goto error;
-	  logC("%d:%d ",ret,cdda_milliseconds(d));
-
-	  /* some drives can lose sync and perform an internal resync,
-	     which can also cause readahead to restart.  If we see
-	     seek-like delays during the initial cahe load, retry the
-	     preload */
-
-	  sofar+=ret;
-	}
-	
-	printC(".");
-
-	/* what we'd predict is needed to let the readahead process work. */
-	{
-	  int usec=mspersector*(readahead)*(4+i)*500;
-	  int max= 13000*2*readahead; /* corresponds to .5x */
-	  if(usec>max)usec=max;
-	  logC("sleep=%dus ",usec);
-	  usleep(usec);
-	}
-	
-	/* seek to offset+cachesize+readahead */
-	ret = cdda_read(d,NULL,offset+cachesize+readahead-1,1);
-	if(ret<=0)break;
-	logC("ahead=%d:%d",readahead,cdda_milliseconds(d));
-	if(cdda_milliseconds(d)<9){
-	  under=1;
-	  break;
-	}else if(i&1){
-	  /* retime the drive just to be conservative */
-	  mspersector=retime_drive(d, progress, log, offset, readahead, mspersector);
-	}
-      }
-      
-      if(under)
-	lower=readahead;
-
-    }
-    readahead=lower;
-  }
-  logC("\n");
-  printC("\r");
-  if(readahead==0){
-    reportC("\tDrive does not read ahead past read cursor (very strange)     \n");
-  }else{
-    reportC("\tDrive readahead past read cursor: %d sector(s)                \n",readahead);
-  }
-  
-  reportC("\tTesting cache tail cursor...");
-
-  while(1){
-    rollbehind=cachesize;
-    
-    for(i=0;i<10 && rollbehind;i++){
-      int sofar=0,ret,retry=0;
-      logC("\n\t\t>>> ");
-      printC(".");
-      while(sofar<cachesize){
-	ret = cdda_read(d,NULL,offset+sofar,cachesize-sofar);
-	if(ret<=0)goto error;
-	logC("%d:%d ",ret,cdda_milliseconds(d));
-	sofar+=ret;
-      }
-    
-      /* Pause what we'd predict is needed to let the readahead process work. */
-      {
-	int usec=mspersector*readahead*5000;
-	logC("\n\t\tsleeping %d microseconds",usec);
-	usleep(usec);
-      }
-      
-      /* read backwards until we seek */
-      logC("\n\t\t<<< ");
-      sofar=rollbehind;
-      while(sofar>0){
-	sofar--;
-	ret = cdda_read(d,NULL,offset+sofar,1);
-	if(ret<=0)break;
-	logC("%d:%d ",sofar,cdda_milliseconds(d));
-	if(cdda_milliseconds(d)>8){
-	  rollbehind=sofar+1;
-	  break;
-	}
-	rollbehind=sofar;
-      }
-    error:
-      if(ret<=0){
-	offset+=cachesize;
-	retry++;
-	if(retry>10 || offset+cachesize>lastsector){
-	  reportC("\n\tToo many read errors while performing drive cache checks;"
-		  "\n\t  aborting test.\n\n");
-	  return(-1);
-	}
-	reportC("\n\tRead error while performing drive cache checks;"
-		"\n\t  choosing new offset and trying again.\n");
-	continue;
-      }
-    }
-
-    /* verify that the drive timing didn't suddenly change */
-    {
-      float newms=retime_drive(d, progress, log, offset, readahead, mspersector);
-      if(newms > mspersector*1.2){
-	mspersector=newms;
-	printC("\r");
-	reportC("\tDrive timing changed during test; retrying...");
-	continue;
-      }
-    }
-    break;
-
-  }
-  
-  logC("\n");
-  printC("\r");
-  if(rollbehind==0){
-    reportC("\tCache tail cursor tied to read cursor                      \n");
-  }else{
-    reportC("\tCache tail rollbehind: %d sector(s)                        \n",rollbehind);
-  }
-  
-  reportC("\tTesting granularity of cache tail");
-
-  while(1){
-    cachegran=cachesize+1;
-    for(i=0;i<10 && cachegran;i++){
-      int sofar=0,ret,retry=0;
-      logC("\n\t\t>>> ");
-      printC(".");
-      while(sofar<cachesize+1){
-	ret = cdda_read(d,NULL,offset+sofar,cachesize-sofar+1);
-	if(ret<=0)goto error2;
-	logC("%d:%d ",ret,cdda_milliseconds(d));
-	sofar+=ret;
-      }
-      
-      /* Pause what we'd predict is needed to let the readahead process work. */
-      {
-	int usec=mspersector*readahead*5000;
-	logC("\n\t\tsleeping %d microseconds",usec);
-	usleep(usec);
-      }
-      
-      /* read backwards until we seek */
-      logC("\n\t\t<<< ");
-      sofar=cachegran;
-      while(sofar){
-	sofar--;
-	ret = cdda_read(d,NULL,offset+sofar,1);
-	if(ret<=0)break;
-	logC("%d:%d ",sofar,cdda_milliseconds(d));
-	if(cdda_milliseconds(d)>8){
-	  cachegran=sofar+1;
-	  break;
-	}
-	cachegran=sofar;
-      }
-    error2:
-      if(ret<=0){
-	offset+=cachesize;
-	retry++;
-	if(retry>10 || offset+cachesize>lastsector){
-	  reportC("\n\tToo many read errors while performing drive cache checks;"
-		  "\n\t  aborting test.\n\n");
-	  return(-1);
-	}
-	reportC("\n\tRead error while performing drive cache checks;"
-		"\n\t  choosing new offset and trying again.\n");
-	continue;
-      }
-    }
-
-    /* verify that the drive timing didn't suddenly change */
-    {
-      float newms=retime_drive(d, progress, log, offset, readahead, mspersector);
-      if(newms > mspersector*1.2){
-	mspersector=newms;
-	printC("\r");
-	reportC("\tDrive timing changed during test; retrying...");
-	continue;
-      }
-    }
-    break;
-    
-  }
-  
-  cachegran -= rollbehind;
-
-  logC("\n");
-  printC("\r");
-  reportC("\tCache tail granularity: %d sector(s)                      \n",cachegran);
-
-
-  /* this drive caches; Determine if the detailed caching behavior fits our model. */
-
-  /* does the readahead cache exceed the maximum Paranoia currently expects? */
-  if(cachesize > CACHEMODEL_SECTORS){
-    reportC("\nWARNING: This drive appears to be caching more sectors of\n"
-	    "           readahead than Paranoia can currently handle!\n");
-    warn=1;
-
-  }
-
-  /* This is similar to the Fast search above, but just in case the
-     cache is being tracked as multiple areas that are treated
-     differently if non-contiguous.... */
-  {
-    int seekoff = cachesize*3;
-    int under=0;
-    reportC("\nVerifying that readahead cache is contiguous...\n");
-    printC("\ttesting");
-  
-    for(i=0;i<30 && !under;i++){
-      printC(".");
-      for(j=0;;j++){
-	int ret1,ret2;
-
-	if(offset+seekoff>lastsector){
-	  reportC("\n\tOut of readable space on CDROM while performing drive checks;"
-		  "\n\t  aborting test.\n\n");
-	  return(-1);
-	}
-	
-
-	ret1 = cdda_read(d,NULL,offset+seekoff,1);
-	logC("\t\t>>> %d:%d ",offset+seekoff,cdda_milliseconds(d));
-	ret2 = cdda_read(d,NULL,offset,1);
-	logC("seek_read:%d\n",cdda_milliseconds(d));
-	
-	if(ret1<=0 || ret2<=0){
-	  offset+=cachesize+100;
-	  if(j==10){
-	    reportC("\n\tToo many read errors while performing drive cache checks;"
-		    "\n\t  aborting test.\n\n");
-	    return(-1);
-	  }
-	  reportC("\n\tRead error while performing drive cache checks;"
-		  "\n\t  choosing new offset and trying again.\n");
-	}else{
-	  if(cdda_milliseconds(d)==-1){
-	    reportC("\n\tTiming error while performing drive cache checks; aborting test.\n");
-	    return(-1);
-	  }else{
-	    if(cdda_milliseconds(d)<9)under=1;
-	    break;
-	  }
-	}
-      }
-    }
-    printC("\r");
-    if(under){
-      reportC("WARNING: Drive cache does not appear to be contiguous!\n");
-      warn=1;
-    }else{
-      reportC("\tDrive cache tests as contiguous.                \n");
-    }
-  }
-
-  /* Verify that a read that begins before the cached readahead dumps
-     the entire readahead cache */
-
-  /* This is tricky because we can't simply read a one sector
-     back seek, then rely on timing/seeking of subsequent sectors; the
-     drive may well not seek ahead if reading linearly would be faster
-     (and it often will be), and simply reading haead after the seek
-     and watching timing will be inaccurate because the drive may roll
-     some readahead into the initial seek before returning the first
-     block. */
-
-  /* we will need to use the timing of reading from media in one form
-     or another and thus need to guard against slow bus transfer times
-     [eg, no DMA] swamping the actual read time from media. */
-
-  /* sample cache access for ten realtime seconds. */
-  //{
-    //int cachems;
-
-    //reportC("\nVerifying that seeking before cache dumps readahead...");
-    //reportC("\n\tSampling cache timing... ");
-  //}
-
-
-  /* Check to see that cdda_clear_cache clears the specified cache area */
-
-  /* Does cdda_clear_cache result in noncontiguous cache areas? */
-
-  return warn;
-}
-
-

Modified: trunk/cdparanoia/paranoia/cdda_paranoia.h
===================================================================
--- trunk/cdparanoia/paranoia/cdda_paranoia.h	2008-09-04 18:22:46 UTC (rev 15259)
+++ trunk/cdparanoia/paranoia/cdda_paranoia.h	2008-09-04 19:02:47 UTC (rev 15260)
@@ -47,6 +47,5 @@
 extern int16_t *paranoia_read_limited(cdrom_paranoia *p,void(*callback)(long,int),int maxretries);
 extern void paranoia_free(cdrom_paranoia *p);
 extern void paranoia_overlapset(cdrom_paranoia *p,long overlap);
-extern int paranoia_analyze_verify(cdrom_drive *d, FILE *progress, FILE *log);
-
+extern int paranoia_cachemodel_size(cdrom_paranoia *p,int sectors);
 #endif

Modified: trunk/cdparanoia/paranoia/p_block.c
===================================================================
--- trunk/cdparanoia/paranoia/p_block.c	2008-09-04 18:22:46 UTC (rev 15259)
+++ trunk/cdparanoia/paranoia/p_block.c	2008-09-04 19:02:47 UTC (rev 15260)
@@ -319,7 +319,7 @@
   p->fragments=new_list((void *)&i_vfragment_constructor,
 			(void *)&i_v_fragment_destructor);
 
-  p->readahead=600;
+  p->readahead=CACHEMODEL_SECTORS;
   p->sortcache=sort_alloc(p->readahead*CD_FRAMEWORDS);
   p->d=d;
   p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS;
@@ -334,3 +334,10 @@
   return(p);
 }
 
+/* sectors < 0 indicates a query.  Returns the number of sectors before the call */
+int paranoia_cachemodel_size(cdrom_paranoia *p,int sectors){
+  int ret = p->readahead;
+  if(sectors>=0)
+    p->readahead=sectors;
+  return ret;
+}



More information about the commits mailing list