summaryrefslogtreecommitdiff
path: root/android-tools/jiffy_tick.txt
blob: 6eb1ae6855f80a8cd57656b2c0cbf92d130680a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
https://en.wikipedia.org/wiki/Jiffy_(time)
In computing, a jiffy was originally the time between two ticks of the system timer interrupt.[4] It is not an absolute time interval unit, since its duration depends on the clock interrupt frequency of the particular hardware platform.

http://man7.org/linux/man-pages/man7/time.7.html
the software clock maintained by the kernel which measures time in jiffies.

The size of a jiffy is determined by the value of the kernel constant HZ.

The times(2) system call is a special case.  It reports times with a
granularity defined by the kernel constant USER_HZ.  User-space
applications can determine the value of this constant using
sysconf(_SC_CLK_TCK).



programmable clocks typically have several modes of operation: one-shot mode
and square-wave mode. In square-wave mode, after counter getting to zero and
causing the interrupt, the holding register is automatically copied into the counter,
and the whole process is repeated again indefinitely. These periodic interrupts
are called clock ticks.

The quantum is the number of clock ticks the theread may continue to run for.
In the currect Linux version, the clock runs at 1000HZ, and each tick is 1ms,
which is called a jiffy


/proc/uptime
    fs/proc/uptime.c
        static int uptime_proc_show(struct seq_file *m, void *v)
        {
            struct timespec uptime;
            struct timespec idle;
            u64 idletime;
            u64 nsec;
            u32 rem;
            int i;

            idletime = 0;
            for_each_possible_cpu(i)
                idletime += (__force u64) kcpustat_cpu(i).cpustat[CPUTIME_IDLE];

                get_monotonic_boottime(&uptime);
                nsec = cputime64_to_jiffies64(idletime) * TICK_NSEC;
                idle.tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem);
                idle.tv_nsec = rem;
                seq_printf(m, "%lu.%02lu %lu.%02lu\n",
                        (unsigned long) uptime.tv_sec,
                        (uptime.tv_nsec / (NSEC_PER_SEC / 100)),
                        (unsigned long) idle.tv_sec,
                        (idle.tv_nsec / (NSEC_PER_SEC / 100)));
                return 0;
        }


    ./include/asm-generic/param.h
        #ifndef __ASM_GENERIC_PARAM_H
        #define __ASM_GENERIC_PARAM_H

        #include <uapi/asm-generic/param.h>

        # undef HZ
        # define HZ     CONFIG_HZ   /* Internal kernel timer frequency */
        # define USER_HZ    100     /* some user interfaces are */
        # define CLOCKS_PER_SEC (USER_HZ)       /* in "ticks" like times() */
        #endif /* __ASM_GENERIC_PARAM_H */

    include/linux/timekeeping.h
        /**
         * ktime_get_boottime - Returns monotonic time since boot in ktime_t format
         *
         * This is similar to CLOCK_MONTONIC/ktime_get, but also includes the
         * time spent in suspend.
         */
        static inline ktime_t ktime_get_boottime(void) {
             return ktime_get_with_offset(TK_OFFS_BOOT);
        }

        /*
         * Timespec interfaces utilizing the ktime based ones
         */
        static inline void get_monotonic_boottime(struct timespec *ts) {
            *ts = ktime_to_timespec(ktime_get_boottime());
        }

        static inline void get_monotonic_boottime64(struct timespec64 *ts)
        {
            *ts = ktime_to_timespec64(ktime_get_boottime());
        }


    include/linux/ktime.h
        /* Map the ktime_t to timespec conversion to ns_to_timespec function */
        #define ktime_to_timespec(kt)       ns_to_timespec((kt).tv64)

        /* Map the ktime_t to timespec conversion to ns_to_timespec function */
        #define ktime_to_timespec64(kt)     ns_to_timespec64((kt).tv64)



About the process start time in /proc/pid/stat:
http://man7.org/linux/man-pages/man5/proc.5.html
(22) starttime  %llu
    The time the process started after system boot.  In
    kernels before Linux 2.6, this value was expressed
    in jiffies.  Since Linux 2.6, the value is expressed
    in clock ticks (divide by sysconf(_SC_CLK_TCK)).

    The format for this field was %lu before Linux 2.6.

kernel side source:
    fs/proc/base.c
        static const struct pid_entry tgid_base_stuff[] = {
            ...
            ONE("stat",       S_IRUGO, proc_tgid_stat),
            ...
        }

    fs/proc/array.c
        int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns,
            struct pid *pid, struct task_struct *task)
        {
            return do_task_stat(m, ns, pid, task, 1);
        }

        static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
            struct pid *pid, struct task_struct *task, int whole)
        {
            ...
            unsigned long long start_time;
            ...
            /* convert nsec -> ticks */
            start_time = nsec_to_clock_t(task->real_start_time);
            ...
            seq_put_decimal_ull(m, " ", start_time);
            ...
        }

    kernel/fork.c
        static __latent_entropy struct task_struct *copy_process(...){
            ...
            p->start_time = ktime_get_ns();
            p->real_start_time = ktime_get_boot_ns();
            ...
        }
    include/linux/timekeeping.h
        static inline u64 ktime_get_ns(void) {
            return ktime_to_ns(ktime_get());
        }
        static inline u64 ktime_get_boot_ns(void) {
            return ktime_to_ns(ktime_get_boottime());
        }

    include/linux/ktime.h:115:#define ktime_to_ns(kt)           ((kt).tv64)

    kernel/time/time.c
        u64 nsec_to_clock_t(u64 x)
        {
        #if (NSEC_PER_SEC % USER_HZ) == 0
            return div_u64(x, NSEC_PER_SEC / USER_HZ);
        #elif (USER_HZ % 512) == 0
            return div_u64(x * USER_HZ / 512, NSEC_PER_SEC / 512);
        #else
            /*
             * max relative error 5.7e-8 (1.8s per year) for USER_HZ <= 1024,
             * overflow after 64.99 years.
             * exact for HZ=60, 72, 90, 120, 144, 180, 300, 600, 900, ...
             */
            return div_u64(x * 9, (9ull * NSEC_PER_SEC + (USER_HZ / 2)) / USER_HZ);
        #endif
        }

    include/linux/time64.h:36:#define NSEC_PER_SEC  1000000000L
    include/asm-generic/param.h
        # undef HZ
        # define HZ     CONFIG_HZ   /* Internal kernel timer frequency */
        # define USER_HZ    100     /* some user interfaces are */
        # define CLOCKS_PER_SEC (USER_HZ)       /* in "ticks" like times() */



The start time of init process is around 0,
it seems not the time that the real /init command in the root direcotry get started.
Need to check how the init command is called from kernel side.
    [    0.000000] arm_arch_timer: Architected cp15 timer(s) running at 1.20MHz (phys).
    [    0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x11b661f8e, max_idle_ns: 1763180809113 ns
    [    0.000005] sched_clock: 56 bits at 1200kHz, resolution 833ns, wraps every 4398046510838ns
    [    0.000096] clocksource: arm,sp804: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 99544814920 ns
    [    0.000105] sched_clock: 32 bits at 19MHz, resolution 52ns, wraps every 111848106981ns
    [    0.000650] Console: colour dummy device 80x25
    [    0.000672] Calibrating delay loop (skipped), value calculated using timer frequency.. 2.40 BogoMIPS (lpj=4800)
    [    0.000684] pid_max: default: 32768 minimum: 301
    [    0.000835] Security Framework initialized
    [    0.000844] SELinux:  Initializing.
    [    0.000955] Mount-cache hash table entries: 4096 (order: 3, 32768 bytes)
    [    0.000963] Mountpoint-cache hash table entries: 4096 (order: 3, 32768 bytes)
    [    0.001807] ===LIUYQ pid=1, real_start_time=0 <===   [    0.001814] ===LIUYQ pid=1, tsk->comm=swapper/0, real_start_time=0
    [    0.001853] ===LIUYQ pid=2, real_start_time=0
    [    0.002682] sched-energy: Sched-energy-costs installed from DT
    [    0.002696] CPU0: update cpu_capacity 1024
    [    0.002717] ASID allocator initialised with 65536 entries
    [    0.002780] ===LIUYQ pid=3, real_start_time=0
    ...
    [   12.736070] (stk) : timed out waiting for ldisc to be un-installed
    [   12.810921] Freeing unused kernel memory: 2304K (ffffffc000f60000 - ffffffc0011a0000)
    [   12.818963] ===LIUYQ /init was called for as init <=== printed from init/main.c in kernel
    [   12.826774] init: init first stage started!

Android uses initramfs, which /init command is used as the first userspace command:
https://wiki.gentoo.org/wiki/Custom_Initramfs
    CONFIG_INITRAMFS_SOURCE=""
    CONFIG_BLK_DEV_INITRD=y
init/main.c
    // start_kernel is called in the head.S or similar files in arch directories
    asmlinkage __visible void __init start_kernel(void) {}
        -> static noinline void __ref rest_init(void) ()
            -> static int __ref kernel_init(void *unused)
                -> kernel_init_freeable();
                    -> static noinline void __init kernel_init_freeable(void){}
                        ->  if (!ramdisk_execute_command) ramdisk_execute_command = "/init";

    static int __ref kernel_init(void *unused){
        kernel_init_freeable();
        ...
        if (ramdisk_execute_command) {
            ret = run_init_process(ramdisk_execute_command);
            ...
        }
        ...
    }

    static int run_init_process(const char *init_filename){
        argv_init[0] = init_filename;
        return do_execve(getname_kernel(init_filename),
                (const char __user *const __user *)argv_init,
                (const char __user *const __user *)envp_init);
    }

kernel/linaro/hisilicon/fs/exec.c:
    do_execve -> do_execveat_common -> exec_binprm


out/host/linux-x86/bin/mkbootfs -d out/target/product/hikey/system out/target/product/hikey/root | out/host/linux-x86/bin/minigzip > out/target/product/hikey/ramdisk.img

out/host/linux-x86/bin/mkbootimg  --kernel out/target/product/hikey/kernel --ramdisk out/target/product/hikey/ramdisk.img --cmdline "console=ttyFIQ0 androidboot.console=ttyFIQ0 androidboot.hardware=hikey firmware_class.path=/system/etc/firmware efi=noruntime printk.devkmsg=on printk.devkmsg=on buildvariant=userdebug" --os_version 7.1.2 --os_patch_level 2017-04-05  --output out/target/product/hikey/boot.img