Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / obdclass / lu_time.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Lustre Time Tracking.
5  *
6  *  Copyright (C) 2006 Cluster File Systems, Inc.
7  *   Author: Nikita Danilov <nikita@clusterfs.com>
8  *
9  *   This file is part of the Lustre file system, http://www.lustre.org
10  *   Lustre is a trademark of Cluster File Systems, Inc.
11  *
12  *   You may have signed or agreed to another license before downloading
13  *   this software.  If so, you are bound by the terms and conditions
14  *   of that agreement, and the following does not apply to you.  See the
15  *   LICENSE file included with this distribution for more information.
16  *
17  *   If you did not agree to a different license, then this copy of Lustre
18  *   is open source software; you can redistribute it and/or modify it
19  *   under the terms of version 2 of the GNU General Public License as
20  *   published by the Free Software Foundation.
21  *
22  *   In either case, Lustre is distributed in the hope that it will be
23  *   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
24  *   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  *   license text for more details.
26  *
27  * These are the only exported functions, they provide some generic
28  * infrastructure for managing object devices
29  */
30
31 #define DEBUG_SUBSYSTEM S_CLASS
32 #ifndef EXPORT_SYMTAB
33 # define EXPORT_SYMTAB
34 #endif
35
36 /* OBD_{ALLOC,FREE}_PTR() */
37 #include <obd_support.h>
38 #include <lprocfs_status.h>
39 #include <lu_object.h>
40 #include <lu_time.h>
41
42 enum {
43         LU_TIME_DEPTH_MAX = 16
44 };
45
46 struct lu_time_data {
47         int                ltd_tos; /* top of the stack */
48         unsigned long long ltd_timestamp[LU_TIME_DEPTH_MAX];
49 };
50
51 /* context key constructor/destructor: lu_time_key_init, lu_time_key_fini */
52 LU_KEY_INIT_FINI(lu_time, struct lu_time_data);
53
54 void lu_time_key_exit(const struct lu_context *ctx,
55                       struct lu_context_key *key, void *data)
56 {
57         struct lu_time_data *value = data;
58         LASSERT(value->ltd_tos == 0);
59 }
60
61 /*
62  * Key, holding temporary buffer. This key is registered very early by
63  * lu_global_init().
64  */
65 static struct lu_context_key lu_time_key = {
66         .lct_tags = LCT_MD_THREAD|LCT_DT_THREAD|LCT_CL_THREAD,
67         .lct_init = lu_time_key_init,
68         .lct_fini = lu_time_key_fini,
69         .lct_exit = lu_time_key_exit
70 };
71
72 int lu_time_global_init(void)
73 {
74         LU_CONTEXT_KEY_INIT(&lu_time_key);
75         return lu_context_key_register(&lu_time_key);
76 }
77
78 void lu_time_global_fini(void)
79 {
80         lu_context_key_degister(&lu_time_key);
81 }
82
83 int lu_time_named_init(struct lprocfs_stats **stats, const char *name,
84                        cfs_proc_dir_entry_t *entry,
85                        const char **names, int nr)
86 {
87         int result;
88         int i;
89
90         ENTRY;
91
92         *stats = NULL;
93         if (nr == 0)
94                 RETURN(0);
95
96         *stats = lprocfs_alloc_stats(nr, 0);
97         if (*stats != NULL) {
98                 result = lprocfs_register_stats(entry, name, *stats);
99                 if (result == 0) {
100                         for (i = 0; i < nr; ++i) {
101                                 lprocfs_counter_init(*stats, i,
102                                                      LPROCFS_CNTR_AVGMINMAX,
103                                                      names[i], "usec");
104                         }
105                 }
106         } else
107                 result = -ENOMEM;
108
109         if (result != 0)
110                 lu_time_fini(stats);
111
112         RETURN(result);
113 }
114 EXPORT_SYMBOL(lu_time_named_init);
115
116 int lu_time_init(struct lprocfs_stats **stats, cfs_proc_dir_entry_t *entry,
117                  const char **names, int nr)
118 {
119         return lu_time_named_init(stats, "stats", entry, names, nr);
120 }
121 EXPORT_SYMBOL(lu_time_init);
122
123 void lu_time_fini(struct lprocfs_stats **stats)
124 {
125         if (*stats != NULL) {
126                 lprocfs_free_stats(stats);
127                 *stats = NULL;
128         }
129 }
130 EXPORT_SYMBOL(lu_time_fini);
131
132 static inline struct lu_time_data *lu_time_data_get(const struct lu_env *env)
133 {
134         return lu_context_key_get(&env->le_ctx, &lu_time_key);
135 }
136
137 int lu_time_is_clean(const struct lu_env *env)
138 {
139         return lu_time_data_get(env)->ltd_tos == 0;
140 }
141 EXPORT_SYMBOL(lu_time_is_clean);
142
143 /* from sleepometer by Andrew Morton */
144 unsigned long long lu_time_stamp_get(void)
145 {
146         /*
147          * Return timestamp with microsecond precision. This has to be cheap.
148          */
149 //#ifdef CONFIG_X86 
150 #if defined(CONFIG_X86) && !defined(CONFIG_X86_64)
151         /*
152          * do_gettimeofday() goes backwards sometimes :(.  Usethe TSC
153          */
154         unsigned long long ret;
155
156         rdtscll(ret);
157         do_div(ret, cpu_khz / 1000);
158         return ret;
159 #else
160         struct timeval now;
161         unsigned long long ret;
162
163         do_gettimeofday(&now);
164         ret = now.tv_sec;
165         ret *= 1000000;
166         ret += now.tv_usec;
167         return ret;
168 #endif
169 }
170 /*
171  * Export it, but do not advertise in headers. This is limited use only.
172  */
173 EXPORT_SYMBOL(lu_time_stamp_get);
174
175 void lu_lprocfs_time_start(const struct lu_env *env)
176 {
177         struct lu_time_data *ltd = lu_time_data_get(env);
178
179         LASSERT(0 <= ltd->ltd_tos);
180         LASSERT(ltd->ltd_tos < ARRAY_SIZE(ltd->ltd_timestamp));
181         ltd->ltd_timestamp[ltd->ltd_tos++] = lu_time_stamp_get();
182 }
183 EXPORT_SYMBOL(lu_lprocfs_time_start);
184
185 void lu_lprocfs_time_end(const struct lu_env *env,
186                          struct lprocfs_stats *stats, int idx)
187 {
188         struct lu_time_data *ltd = lu_time_data_get(env);
189         long long diff;
190
191         --ltd->ltd_tos;
192         LASSERT(0 <= ltd->ltd_tos);
193         LASSERT(ltd->ltd_tos < ARRAY_SIZE(ltd->ltd_timestamp));
194         diff = lu_time_stamp_get() - ltd->ltd_timestamp[ltd->ltd_tos];
195         if (diff >= 0 && stats != NULL)
196                 lprocfs_counter_add(stats, idx, diff);
197 }
198 EXPORT_SYMBOL(lu_lprocfs_time_end);