示例#1
0
static void test_readahead(void)
{
	unsigned long read_bytes, read_bytes_ra;
	long usec, usec_ra;
	unsigned long cached_max, cached_low, cached, cached_ra;
	char proc_io_fname[128];
	sprintf(proc_io_fname, "/proc/%u/io", getpid());

	/* find out how much can cache hold if we read whole file */
	read_testfile(0, testfile, testfile_size, &read_bytes, &usec, &cached);
	cached_max = get_cached_size();
	sync();
	drop_caches();
	cached_low = get_cached_size();
	cached_max = cached_max - cached_low;

	tst_resm(TINFO, "read_testfile(0)");
	read_testfile(0, testfile, testfile_size, &read_bytes, &usec, &cached);
	cached = cached - cached_low;

	sync();
	drop_caches();
	cached_low = get_cached_size();
	tst_resm(TINFO, "read_testfile(1)");
	read_testfile(1, testfile, testfile_size, &read_bytes_ra,
		      &usec_ra, &cached_ra);
	cached_ra = cached_ra - cached_low;

	tst_resm(TINFO, "read_testfile(0) took: %ld usec", usec);
	tst_resm(TINFO, "read_testfile(1) took: %ld usec", usec_ra);
	if (has_file(proc_io_fname, 0)) {
		tst_resm(TINFO, "read_testfile(0) read: %ld bytes", read_bytes);
		tst_resm(TINFO, "read_testfile(1) read: %ld bytes",
			 read_bytes_ra);
		/* actual number of read bytes depends on total RAM */
		if (read_bytes_ra < read_bytes)
			tst_resm(TPASS, "readahead saved some I/O");
		else
			tst_resm(TFAIL, "readahead failed to save any I/O");
	} else {
		tst_resm(TCONF, "Your system doesn't have /proc/pid/io,"
			 " unable to determine read bytes during test");
	}

	tst_resm(TINFO, "cache can hold at least: %ld kB", cached_max);
	tst_resm(TINFO, "read_testfile(0) used cache: %ld kB", cached);
	tst_resm(TINFO, "read_testfile(1) used cache: %ld kB", cached_ra);

	if (cached_max * 1024 >= testfile_size) {
		/*
		 * if cache can hold ~testfile_size then cache increase
		 * for readahead should be at least testfile_size/2
		 */
		if (cached_ra * 1024 > testfile_size / 2)
			tst_resm(TPASS, "using cache as expected");
		else
			tst_resm(TWARN, "using less cache than expected");
	} else {
		tst_resm(TCONF, "Page cache on your system is too small "
			 "to hold whole testfile.");
	}
}
示例#2
0
/* read_testfile - mmap testfile and read every page.
 * This functions measures how many I/O and time it takes to fully
 * read contents of test file.
 *
 * @do_readahead: call readahead prior to reading file content?
 * @fname: name of file to test
 * @fsize: how many bytes to read/mmap
 * @read_bytes: returns difference of bytes read, parsed from /proc/<pid>/io
 * @usec: returns how many microsecond it took to go over fsize bytes
 * @cached: returns cached kB from /proc/meminfo
 */
static void read_testfile(int do_readahead, const char *fname, size_t fsize,
			  unsigned long *read_bytes, long *usec,
			  unsigned long *cached)
{
	int fd;
	size_t i;
	long read_bytes_start;
	unsigned char *p, tmp;
	unsigned long time_start_usec, time_end_usec;
	off_t offset;
	struct timeval now;

	fd = open(fname, O_RDONLY);
	if (fd < 0)
		tst_brkm(TBROK | TERRNO, cleanup, "Failed to open %s", fname);

	if (do_readahead) {
		/* read ahead in chunks, 2MB is maximum since 3.15-rc1 */
		for (i = 0; i < fsize; i += 2*1024*1024) {
			TEST(ltp_syscall(__NR_readahead, fd,
				(off64_t) i, 2*1024*1024));
			if (TEST_RETURN != 0)
				break;
		}
		check_ret(0);
		*cached = get_cached_size();

		/* offset of file shouldn't change after readahead */
		offset = lseek(fd, 0, SEEK_CUR);
		if (offset == (off_t) - 1)
			tst_brkm(TBROK | TERRNO, cleanup, "lseek failed");
		if (offset == 0)
			tst_resm(TPASS, "offset is still at 0 as expected");
		else
			tst_resm(TFAIL, "offset has changed to: %lu", offset);
	}

	if (gettimeofday(&now, NULL) == -1)
		tst_brkm(TBROK | TERRNO, cleanup, "gettimeofday failed");
	time_start_usec = now.tv_sec * 1000000 + now.tv_usec;
	read_bytes_start = get_bytes_read();

	p = mmap(NULL, fsize, PROT_READ, MAP_SHARED | MAP_POPULATE, fd, 0);
	if (p == MAP_FAILED)
		tst_brkm(TBROK | TERRNO, cleanup, "mmap failed");

	/* for old kernels, where MAP_POPULATE doesn't work, touch each page */
	tmp = 0;
	for (i = 0; i < fsize; i += pagesize)
		tmp = tmp ^ p[i];
	/* prevent gcc from optimizing out loop above */
	if (tmp != 0)
		tst_brkm(TBROK, NULL, "This line should not be reached");

	if (!do_readahead)
		*cached = get_cached_size();

	if (munmap(p, fsize) == -1)
		tst_brkm(TBROK | TERRNO, cleanup, "munmap failed");

	*read_bytes = get_bytes_read() - read_bytes_start;
	if (gettimeofday(&now, NULL) == -1)
		tst_brkm(TBROK | TERRNO, cleanup, "gettimeofday failed");
	time_end_usec = now.tv_sec * 1000000 + now.tv_usec;
	*usec = time_end_usec - time_start_usec;

	if (close(fd) == -1)
		tst_brkm(TBROK | TERRNO, cleanup, "close failed");
}
示例#3
0
/* read_testfile - mmap testfile and read every page.
 * This functions measures how many I/O and time it takes to fully
 * read contents of test file.
 *
 * @do_readahead: call readahead prior to reading file content?
 * @fname: name of file to test
 * @fsize: how many bytes to read/mmap
 * @read_bytes: returns difference of bytes read, parsed from /proc/<pid>/io
 * @usec: returns how many microsecond it took to go over fsize bytes
 * @cached: returns cached kB from /proc/meminfo
 */
static void read_testfile(int do_readahead, const char *fname, size_t fsize,
			  unsigned long *read_bytes, long *usec,
			  unsigned long *cached)
{
	int fd;
	size_t i = 0;
	long read_bytes_start;
	unsigned char *p, tmp;
	unsigned long time_start_usec, time_end_usec;
	unsigned long cached_start, max_ra_estimate = 0;
	off_t offset = 0;
	struct timeval now;

	fd = SAFE_OPEN(cleanup, fname, O_RDONLY);

	if (do_readahead) {
		cached_start = get_cached_size();
		do {
			TEST(readahead(fd, offset, fsize - offset));
			if (TEST_RETURN != 0) {
				check_ret(0);
				break;
			}

			/* estimate max readahead size based on first call */
			if (!max_ra_estimate) {
				*cached = get_cached_size();
				if (*cached > cached_start) {
					max_ra_estimate = (1024 *
						(*cached - cached_start));
					tst_resm(TINFO, "max ra estimate: %lu",
						max_ra_estimate);
				}
				max_ra_estimate = MAX(max_ra_estimate,
					MIN_SANE_READAHEAD);
			}

			i++;
			offset += max_ra_estimate;
		} while ((size_t)offset < fsize);
		tst_resm(TINFO, "readahead calls made: %zu", i);
		*cached = get_cached_size();

		/* offset of file shouldn't change after readahead */
		offset = lseek(fd, 0, SEEK_CUR);
		if (offset == (off_t) - 1)
			tst_brkm(TBROK | TERRNO, cleanup, "lseek failed");
		if (offset == 0)
			tst_resm(TPASS, "offset is still at 0 as expected");
		else
			tst_resm(TFAIL, "offset has changed to: %lu", offset);
	}

	if (gettimeofday(&now, NULL) == -1)
		tst_brkm(TBROK | TERRNO, cleanup, "gettimeofday failed");
	time_start_usec = now.tv_sec * 1000000 + now.tv_usec;
	read_bytes_start = get_bytes_read();

	p = mmap(NULL, fsize, PROT_READ, MAP_SHARED | MAP_POPULATE, fd, 0);
	if (p == MAP_FAILED)
		tst_brkm(TBROK | TERRNO, cleanup, "mmap failed");

	/* for old kernels, where MAP_POPULATE doesn't work, touch each page */
	tmp = 0;
	for (i = 0; i < fsize; i += pagesize)
		tmp = tmp ^ p[i];
	/* prevent gcc from optimizing out loop above */
	if (tmp != 0)
		tst_brkm(TBROK, NULL, "This line should not be reached");

	if (!do_readahead)
		*cached = get_cached_size();

	SAFE_MUNMAP(cleanup, p, fsize);

	*read_bytes = get_bytes_read() - read_bytes_start;
	if (gettimeofday(&now, NULL) == -1)
		tst_brkm(TBROK | TERRNO, cleanup, "gettimeofday failed");
	time_end_usec = now.tv_sec * 1000000 + now.tv_usec;
	*usec = time_end_usec - time_start_usec;

	SAFE_CLOSE(cleanup, fd);
}
示例#4
0
/* This is the main function that checks for a cached size and
 * possibly queries the widget class to compute the size if it's
 * not cached. If the for_size here is -1, then get_preferred_width()
 * or get_preferred_height() will be used.
 */
static void
compute_size_for_orientation (GtkWidget         *widget,
                              GtkSizeGroupMode   orientation,
                              gint               for_size,
                              gint              *minimum_size,
                              gint              *natural_size)
{
  CachedSize       *cached_size;
  gboolean          found_in_cache = FALSE;
  gint              min_size = 0;
  gint              nat_size = 0;

  found_in_cache = get_cached_size (widget, orientation, for_size, &cached_size);

  if (!found_in_cache)
    {
      gint adjusted_min, adjusted_natural, adjusted_for_size = for_size;

      gtk_widget_ensure_style (widget);

      if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
        {
          if (for_size < 0)
            {
	      push_recursion_check (widget, orientation, for_size);
              GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_size, &nat_size);
	      pop_recursion_check (widget, orientation);
            }
          else
            {
              gint ignored_position = 0;
              gint minimum_height;
              gint natural_height;

	      /* Pull the base natural height from the cache as it's needed to adjust
	       * the proposed 'for_size' */
	      gtk_widget_get_preferred_height (widget, &minimum_height, &natural_height);

              /* convert for_size to unadjusted height (for_size is a proposed allocation) */
              GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget,
                                                                     GTK_ORIENTATION_VERTICAL,
                                                                     &minimum_height,
								     &natural_height,
                                                                     &ignored_position,
                                                                     &adjusted_for_size);

	      push_recursion_check (widget, orientation, for_size);
              GTK_WIDGET_GET_CLASS (widget)->get_preferred_width_for_height (widget, 
									     MAX (adjusted_for_size, minimum_height),
									     &min_size, &nat_size);
	      pop_recursion_check (widget, orientation);
            }
        }
      else
        {
          if (for_size < 0)
            {
	      push_recursion_check (widget, orientation, for_size);
              GTK_WIDGET_GET_CLASS (widget)->get_preferred_height (widget, &min_size, &nat_size);
	      pop_recursion_check (widget, orientation);
            }
          else
            {
              gint ignored_position = 0;
              gint minimum_width;
              gint natural_width;

	      /* Pull the base natural width from the cache as it's needed to adjust
	       * the proposed 'for_size' */
	      gtk_widget_get_preferred_width (widget, &minimum_width, &natural_width);

              /* convert for_size to unadjusted width (for_size is a proposed allocation) */
              GTK_WIDGET_GET_CLASS (widget)->adjust_size_allocation (widget,
                                                                     GTK_ORIENTATION_HORIZONTAL,
								     &minimum_width,
                                                                     &natural_width,
                                                                     &ignored_position,
                                                                     &adjusted_for_size);

	      push_recursion_check (widget, orientation, for_size);
              GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget, 
									     MAX (adjusted_for_size, minimum_width),
									     &min_size, &nat_size);
	      pop_recursion_check (widget, orientation);
            }
        }

      if (min_size > nat_size)
        {
          g_warning ("%s %p reported min size %d and natural size %d; natural size must be >= min size",
                     G_OBJECT_TYPE_NAME (widget), widget, min_size, nat_size);
        }

      if (orientation == GTK_SIZE_GROUP_HORIZONTAL)
          _gtk_widget_set_width_request_needed (widget, FALSE);
      else
          _gtk_widget_set_height_request_needed (widget, FALSE);

      adjusted_min     = min_size;
      adjusted_natural = nat_size;
      GTK_WIDGET_GET_CLASS (widget)->adjust_size_request (widget,
                                                          orientation == GTK_SIZE_GROUP_HORIZONTAL ?
                                                          GTK_ORIENTATION_HORIZONTAL :
                                                          GTK_ORIENTATION_VERTICAL,
                                                          &adjusted_min,
                                                          &adjusted_natural);

      if (adjusted_min < min_size ||
          adjusted_natural < nat_size)
        {
          g_warning ("%s %p adjusted size %s min %d natural %d must not decrease below min %d natural %d",
                     G_OBJECT_TYPE_NAME (widget), widget,
                     orientation == GTK_SIZE_GROUP_VERTICAL ? "vertical" : "horizontal",
                     adjusted_min, adjusted_natural,
                     min_size, nat_size);
          /* don't use the adjustment */
        }
      else if (adjusted_min > adjusted_natural)
        {
          g_warning ("%s %p adjusted size %s min %d natural %d original min %d natural %d has min greater than natural",
                     G_OBJECT_TYPE_NAME (widget), widget,
                     orientation == GTK_SIZE_GROUP_VERTICAL ? "vertical" : "horizontal",
                     adjusted_min, adjusted_natural,
                     min_size, nat_size);
          /* don't use the adjustment */
        }
      else
        {
          /* adjustment looks good */
          min_size = adjusted_min;
          nat_size = adjusted_natural;
        }

      /* Update size-groups with our request and update our cached requests
       * with the size-group values in a single pass.
       */
      _gtk_size_group_bump_requisition (widget,
					orientation,
					&min_size,
					&nat_size);

      commit_cached_size (widget, orientation, for_size, min_size, nat_size);
    }
  else
    {
      min_size = cached_size->minimum_size;
      nat_size = cached_size->natural_size;
    }

  if (minimum_size)
    *minimum_size = min_size;

  if (natural_size)
    *natural_size = nat_size;

  g_assert (min_size <= nat_size);

  GTK_NOTE (SIZE_REQUEST,
            g_print ("[%p] %s\t%s: %d is minimum %d and natural: %d (hit cache: %s)\n",
                     widget, G_OBJECT_TYPE_NAME (widget),
                     orientation == GTK_SIZE_GROUP_HORIZONTAL ?
                     "width for height" : "height for width" ,
                     for_size, min_size, nat_size,
                     found_in_cache ? "yes" : "no"));

}
示例#5
0
文件: readahead02.c 项目: kraj/ltp
static void test_readahead(unsigned int n)
{
	unsigned long read_bytes, read_bytes_ra;
	long long usec, usec_ra;
	unsigned long cached_high, cached_low, cached, cached_ra;
	int ret;
	struct tcase *tc = &tcases[n];

	tst_res(TINFO, "Test #%d: %s", n, tc->tname);

	if (tc->use_overlay && !ovl_mounted) {
		tst_res(TCONF,
		        "overlayfs is not configured in this kernel.");
		return;
	}

	create_testfile(tc->use_overlay);

	/* find out how much can cache hold if we read whole file */
	read_testfile(tc, 0, testfile, testfile_size, &read_bytes, &usec,
		      &cached);
	cached_high = get_cached_size();
	sync();
	drop_caches();
	cached_low = get_cached_size();
	cached_max = MAX(cached_max, cached_high - cached_low);

	tst_res(TINFO, "read_testfile(0)");
	read_testfile(tc, 0, testfile, testfile_size, &read_bytes, &usec,
		      &cached);
	if (cached > cached_low)
		cached = cached - cached_low;
	else
		cached = 0;

	sync();
	drop_caches();
	cached_low = get_cached_size();
	tst_res(TINFO, "read_testfile(1)");
	ret = read_testfile(tc, 1, testfile, testfile_size, &read_bytes_ra,
		            &usec_ra, &cached_ra);

	if (ret == EINVAL) {
		if (tc->use_fadvise &&
		    (!tc->use_overlay || !fadvise_supported)) {
			fadvise_supported = 0;
			tst_res(TCONF, "CONFIG_ADVISE_SYSCALLS not configured "
				"in kernel?");
			return;
		}

		if (!tc->use_overlay || !readahead_supported) {
			readahead_supported = 0;
			tst_res(TCONF, "readahead not supported on %s",
				tst_device->fs_type);
			return;
		}
	}

	if (ret) {
		tst_res(TFAIL | TTERRNO, "%s failed on %s",
			tc->use_fadvise ? "fadvise" : "readahead",
			tc->use_overlay ? "overlayfs" :
			tst_device->fs_type);
		return;
	}

	if (cached_ra > cached_low)
		cached_ra = cached_ra - cached_low;
	else
		cached_ra = 0;

	tst_res(TINFO, "read_testfile(0) took: %lli usec", usec);
	tst_res(TINFO, "read_testfile(1) took: %lli usec", usec_ra);
	if (has_file(PROC_IO_FNAME, 0)) {
		tst_res(TINFO, "read_testfile(0) read: %ld bytes", read_bytes);
		tst_res(TINFO, "read_testfile(1) read: %ld bytes",
			read_bytes_ra);
		/* actual number of read bytes depends on total RAM */
		if (read_bytes_ra < read_bytes)
			tst_res(TPASS, "readahead saved some I/O");
		else
			tst_res(TFAIL, "readahead failed to save any I/O");
	} else {
		tst_res(TCONF, "Your system doesn't have /proc/self/io,"
			" unable to determine read bytes during test");
	}

	tst_res(TINFO, "cache can hold at least: %ld kB", cached_max);
	tst_res(TINFO, "read_testfile(0) used cache: %ld kB", cached);
	tst_res(TINFO, "read_testfile(1) used cache: %ld kB", cached_ra);

	if (cached_max * 1024 >= testfile_size) {
		/*
		 * if cache can hold ~testfile_size then cache increase
		 * for readahead should be at least testfile_size/2
		 */
		if (cached_ra * 1024 > testfile_size / 2)
			tst_res(TPASS, "using cache as expected");
		else if (!cached_ra)
			tst_res(TFAIL, "readahead failed to use any cache");
		else
			tst_res(TWARN, "using less cache than expected");
	} else {
		tst_res(TCONF, "Page cache on your system is too small "
			"to hold whole testfile.");
	}
}
示例#6
0
文件: readahead02.c 项目: kraj/ltp
/* read_testfile - mmap testfile and read every page.
 * This functions measures how many I/O and time it takes to fully
 * read contents of test file.
 *
 * @do_readahead: call readahead prior to reading file content?
 * @fname: name of file to test
 * @fsize: how many bytes to read/mmap
 * @read_bytes: returns difference of bytes read, parsed from /proc/<pid>/io
 * @usec: returns how many microsecond it took to go over fsize bytes
 * @cached: returns cached kB from /proc/meminfo
 */
static int read_testfile(struct tcase *tc, int do_readahead,
			 const char *fname, size_t fsize,
			 unsigned long *read_bytes, long long *usec,
			 unsigned long *cached)
{
	int fd;
	size_t i = 0;
	long read_bytes_start;
	unsigned char *p, tmp;
	off_t offset = 0;

	fd = SAFE_OPEN(fname, O_RDONLY);

	if (do_readahead) {
		do {
			TEST(tc->readahead(fd, offset, fsize - offset));
			if (TST_RET != 0) {
				SAFE_CLOSE(fd);
				return TST_ERR;
			}

			i++;
			offset += readahead_length;
		} while ((size_t)offset < fsize);
		tst_res(TINFO, "readahead calls made: %zu", i);
		*cached = get_cached_size();

		/* offset of file shouldn't change after readahead */
		offset = SAFE_LSEEK(fd, 0, SEEK_CUR);
		if (offset == 0)
			tst_res(TPASS, "offset is still at 0 as expected");
		else
			tst_res(TFAIL, "offset has changed to: %lu", offset);
	}

	tst_timer_start(CLOCK_MONOTONIC);
	read_bytes_start = get_bytes_read();

	p = SAFE_MMAP(NULL, fsize, PROT_READ, MAP_SHARED | MAP_POPULATE, fd, 0);

	/* for old kernels, where MAP_POPULATE doesn't work, touch each page */
	tmp = 0;
	for (i = 0; i < fsize; i += pagesize)
		tmp = tmp ^ p[i];
	/* prevent gcc from optimizing out loop above */
	if (tmp != 0)
		tst_brk(TBROK, "This line should not be reached");

	if (!do_readahead)
		*cached = get_cached_size();

	SAFE_MUNMAP(p, fsize);

	*read_bytes = get_bytes_read() - read_bytes_start;

	tst_timer_stop();
	*usec = tst_timer_elapsed_us();

	SAFE_CLOSE(fd);
	return 0;
}