Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 2 Mar 2019 21:20:58 -0800
From:      Mark Millard <marklmi@yahoo.com>
To:        FreeBSD PowerPC ML <freebsd-ppc@freebsd.org>, Mark Millard via freebsd-hackers <freebsd-hackers@freebsd.org>
Subject:   powerpc64 on PowerMac G5 4-core (system total): a hack that so far seem to avoid the stuck-sleeping issue
Message-ID:  <B898BF60-2872-4FFC-AD72-A32591BC7D20@yahoo.com>

next in thread | raw e-mail | index | archive | help
[This note goes in a different direction compared to my
prior evidence report for overflows and the later activity
that has been happening for it. This does *not* involve
the patches associated with that report.]

I view the following as an evidence-gathering hack:
showing the change in behavior with the code changes,
not as directly what FreeBSD should do for powerpc64.
In code for defined(__powerpc64__) && defined(AIM)
I freely use knowledge of the PowerMac G5 context
instead of attempting general code.

Also: the code is set up to record some information
that I've been looking at via ddb. The recording is
not part of what changes the behavior but I decided
to show that code too.

It is preliminary, but, so far, the hack has avoided
buf*daemon* threads and pmac_thermal getting stuck
sleeping (or, at least, far less frequently).


The tbr-value hack:

=46rom what I see the G5 various cores have each tbr running at the
same rate but have some some offsets as far as the base time
goes. cpu_mp_unleash does:

        ap_awake =3D 1;

        /* Provide our current DEC and TB values for APs */
        ap_timebase =3D mftb() + 10;
        __asm __volatile("msync; isync");

        /* Let APs continue */
        atomic_store_rel_int(&ap_letgo, 1);

        platform_smp_timebase_sync(ap_timebase, 0);

and machdep_ap_bootstrap does:

        /*
         * Set timebase as soon as possible to meet an implicit =
rendezvous
         * from cpu_mp_unleash(), which sets ap_letgo and then =
immediately
         * sets timebase.
         *
         * Note that this is instrinsically racy and is only relevant on
         * platforms that do not support better mechanisms.
         */
        platform_smp_timebase_sync(ap_timebase, 1);


which attempts to set the tbrs appropriately.

But on small scales of differences the various tbr
values from different cpus end up not well ordered
relative to time, synchronizes with, and the like.
Only large enough differences can well indicate an
ordering of interest.

Note: tc->tc_get_timecount(tc) only provides the
least signficant 32 bits of the tbr value.
th->th_offset_count is also 32 bits and based on
truncated tbr values.

So I made binuptime avoid finishing when it sees
a small (<0x10) step backwards for a new
tc->tc_get_timecount(tc) value vs. the existing
th->th_offset_count value (values strongly tied
to powerpc64 tbr values):

void
binuptime(struct bintime *bt)
{
        struct timehands *th;
        u_int gen;

        struct bintime old_bt=3D *bt; // HACK!!!
        struct timecounter *tc; // HACK!!!
        u_int tim_cnt, tim_offset, tim_diff; // HACK!!!
        uint64_t freq, scale_factor, diff_scaled; // HACK!!!

        u_int try_cnt=3D 0ull; // HACK!!!

        do {
                do { // HACK!!!
                    th =3D timehands;
                    tc =3D th->th_counter;
                    gen =3D atomic_load_acq_int(&th->th_generation);
                    tim_cnt=3D tc->tc_get_timecount(tc);
                    tim_offset=3D th->th_offset_count;
                } while (tim_cnt<tim_offset && tim_offset-tim_cnt<0x10);
                *bt =3D th->th_offset;
                tim_diff=3D (tim_cnt - tim_offset) & =
tc->tc_counter_mask;
                scale_factor=3D th->th_scale;
                diff_scaled=3D scale_factor * tim_diff;
                bintime_addx(bt, diff_scaled);
                freq=3D tc->tc_frequency;
                atomic_thread_fence_acq();
                try_cnt++;
        } while (gen =3D=3D 0 || gen !=3D th->th_generation);

        if (*(volatile uint64_t*)0xc000000000000020=3D=3D0u && =
(0xffffffffffffffffull/scale_factor)<tim_diff) { // HACK!!!
                *(volatile uint64_t*)0xc000000000000020=3D =
bttosbt(old_bt);
                *(volatile uint64_t*)0xc000000000000028=3D bttosbt(*bt);
                *(volatile uint64_t*)0xc000000000000030=3D freq;
                *(volatile uint64_t*)0xc000000000000038=3D scale_factor;
                *(volatile uint64_t*)0xc000000000000040=3D tim_offset;
                *(volatile uint64_t*)0xc000000000000048=3D tim_cnt;
                *(volatile uint64_t*)0xc000000000000050=3D tim_diff;
                *(volatile uint64_t*)0xc000000000000058=3D try_cnt;
                *(volatile uint64_t*)0xc000000000000060=3D diff_scaled;
                *(volatile uint64_t*)0xc000000000000068=3D =
scale_factor*freq;
                __asm__ ("sync");
        } else if (*(volatile uint64_t*)0xc0000000000000a0=3D=3D0u && =
(0xffffffffffffffffull/scale_factor)<tim_diff) { // HACK!!!
                *(volatile uint64_t*)0xc0000000000000a0=3D =
bttosbt(old_bt);
                *(volatile uint64_t*)0xc0000000000000a8=3D bttosbt(*bt);
                *(volatile uint64_t*)0xc0000000000000b0=3D freq;
                *(volatile uint64_t*)0xc0000000000000b8=3D scale_factor;
                *(volatile uint64_t*)0xc0000000000000c0=3D tim_offset;
                *(volatile uint64_t*)0xc0000000000000c8=3D tim_cnt;
                *(volatile uint64_t*)0xc0000000000000d0=3D tim_diff;
                *(volatile uint64_t*)0xc0000000000000d8=3D try_cnt;
                *(volatile uint64_t*)0xc0000000000000e0=3D diff_scaled;
                *(volatile uint64_t*)0xc0000000000000e8=3D =
scale_factor*freq;
                __asm__ ("sync");
        }
}
#else
. . .
#endif

So far as I can tell, the FreeBSD code is not designed to deal
with small differences in tc->tc_get_timecount(tc) not actually
indicating a useful < vs. =3D=3D vs. > ordering relation uniquely.

(I make no claim that the hack is a proper way to deal with
such.)

=3D=3D=3D
Mark Millard
marklmi at yahoo.com
( dsl-only.net went
away in early 2018-Mar)




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?B898BF60-2872-4FFC-AD72-A32591BC7D20>