182498Sroberto#! @PATH_PERL@ -w
282498Sroberto
382498Srobertodie "perl5 needed\n" unless ($] > 5);
482498Sroberto
582498Srobertouse Getopt::Std;
682498Srobertouse vars qw($opt_n);
782498Sroberto
882498Srobertogetopts('d:nt:');
982498Sroberto
1082498Sroberto#chop($ncpu = `sysctl -n hw.ncpu`);
1182498Sroberto#die "Found $ncpu CPUs; can only be run on systems with 1 CPU.\n" if ($ncpu > 1);
1282498Sroberto
1382498Sroberto$driftfile = "/etc/ntp.drift";
1482498Sroberto$driftfile = $opt_d if defined($opt_d);
1582498Sroberto
1682498Srobertochop($timer = `sysctl -n kern.timecounter.hardware 2> /dev/null`);
1782498Sroberto
1882498Sroberto$timer =~ tr/\U/\L/;
1982498Sroberto
2082498Srobertoif ($timer eq '') {
2182498Sroberto  open(DM, "/var/run/dmesg.boot");
2282498Sroberto  while(<DM>) {
2382498Sroberto    # Timecounter "i8254"  frequency 1193182 Hz
2482498Sroberto    if (/^Timecounter "(\w+)"\s+/) {
2582498Sroberto      $timer = $1;
2682498Sroberto      last;
2782498Sroberto    }
2882498Sroberto  }
2982498Sroberto  close(DM);
3082498Sroberto}
3182498Sroberto
3282498Sroberto$opt_t = $timer if !defined($opt_t);
3382498Sroberto
3482498Srobertoif ($timer ne '') {		# $timer found...
3582498Sroberto  if ($opt_t ne  '') {		# - and $opt_t found
3682498Sroberto    if ($timer ne $opt_t) {	# - - and they differ
3782498Sroberto      warn "You specified a $opt_t timer but I detected a $timer timer.\n";
3882498Sroberto      usage();
3982498Sroberto      exit 1;
4082498Sroberto    } else {			# - - and they are the same
4182498Sroberto      ;
4282498Sroberto    }
4382498Sroberto  } else {			# - but no $opt_t specified; this is OK
4482498Sroberto    ;
4582498Sroberto  }
4682498Sroberto} else {			# No $timer found...
4782498Sroberto  if ($opt_t ne '') {		# - but $opt_t was specified
4882498Sroberto    $timer = $opt_t;		# - - so use it.
4982498Sroberto  } else {			# - and neither was $opt_t
5082498Sroberto    warn "I can't tell what timer you have.  Please specify one.\n";
5182498Sroberto    usage();
5282498Sroberto    exit 1;
5382498Sroberto  }
5482498Sroberto}
5582498Sroberto
5682498Srobertoopen(DF, $driftfile) || die "Can't open driftfile ($driftfile): $!\n";
5782498Srobertowhile(<DF>) {
5882498Sroberto    chop;
5982498Sroberto    if (/^(-?\d+\.\d+)(\s\d)?$/) {
6082498Sroberto	$drift = $1;
6182498Sroberto    } else {
6282498Sroberto	die "Bogus value in driftfile $driftfile: <$_>\n";
6382498Sroberto    }
6482498Sroberto}
6582498Srobertoclose(DF);
6682498Sroberto
6782498Srobertoprint "NTP drift is <$drift>\n";
6882498Sroberto
6982498Sroberto# Convert from NTP's idea of PPM to a decimal equivalent
7082498Sroberto$freq_adj = int ( $drift * ( 10 ** 6 / 2 ** 20) );
7182498Srobertoprint "normalized freq_adj  is <$freq_adj>\n";
7282498Sroberto
7382498Sroberto$freq_adj = int ( ( $freq_adj - 1 ) / 2 );
7482498Srobertoprint "Applying freq_adj of <".-$freq_adj.">\n";
7582498Sroberto
7682498Sroberto$sysctl = "machdep.".$timer."_freq";
7782498Sroberto
7882498Srobertochop($mach_freq = `sysctl -n $sysctl`);
7982498Sroberto
8082498Srobertoprint "$sysctl is <$mach_freq>\n";
8182498Sroberto
8282498Sroberto$n_mach_freq = $mach_freq - $freq_adj;
8382498Sroberto
8482498Srobertoif (defined($opt_n)) {
8582498Sroberto  print "$sysctl $mach_freq -> $n_mach_freq\n";
8682498Sroberto} else {
8782498Sroberto  print "i8254: ".`sysctl -w $sysctl=$n_mach_freq`;
8882498Sroberto}
8982498Sroberto
9082498Srobertosub usage {
9182498Sroberto  print STDERR <<EOUsage
9282498SrobertoUsage: $0 [-d drift_file] [-n] [-t timer]
9382498Srobertowhere "drift_file" defaults to /etc/ntp.drift
9482498Srobertoand "timer" is usually "tsc" or "i8254"
9582498Srobertoand "-n" says "don't really change anything, just say what would happen".
9682498SrobertoEOUsage
9782498Sroberto}
98