| // Copyright 2017 The Crashpad Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "util/linux/proc_stat_reader.h" |
| |
| #include <sys/syscall.h> |
| #include <time.h> |
| #include <unistd.h> |
| |
| #include "base/logging.h" |
| #include "gtest/gtest.h" |
| #include "test/linux/fake_ptrace_connection.h" |
| #include "util/misc/time.h" |
| #include "util/thread/thread.h" |
| |
| namespace crashpad { |
| namespace test { |
| namespace { |
| |
| TEST(ProcStatReader, Basic) { |
| FakePtraceConnection connection; |
| ASSERT_TRUE(connection.Initialize(getpid())); |
| |
| ProcStatReader stat; |
| ASSERT_TRUE(stat.Initialize(&connection, getpid())); |
| |
| timespec boot_time_ts; |
| ASSERT_TRUE(GetBootTime(&boot_time_ts)); |
| timeval boot_time; |
| TimespecToTimeval(boot_time_ts, &boot_time); |
| |
| timeval start_time; |
| ASSERT_TRUE(stat.StartTime(boot_time, &start_time)); |
| |
| time_t now; |
| time(&now); |
| EXPECT_LE(start_time.tv_sec, now); |
| |
| time_t elapsed_sec = now - start_time.tv_sec; |
| |
| timeval user_time; |
| ASSERT_TRUE(stat.UserCPUTime(&user_time)); |
| EXPECT_LE(user_time.tv_sec, elapsed_sec); |
| |
| timeval system_time; |
| ASSERT_TRUE(stat.SystemCPUTime(&system_time)); |
| EXPECT_LE(system_time.tv_sec, elapsed_sec); |
| } |
| |
| pid_t gettid() { |
| return syscall(SYS_gettid); |
| } |
| |
| void GetStartTime(const timeval& boot_time, timeval* start_time) { |
| FakePtraceConnection connection; |
| ASSERT_TRUE(connection.Initialize(getpid())); |
| |
| ProcStatReader stat; |
| ASSERT_TRUE(stat.Initialize(&connection, gettid())); |
| ASSERT_TRUE(stat.StartTime(boot_time, start_time)); |
| } |
| |
| class StatTimeThread : public Thread { |
| public: |
| StatTimeThread(const timeval& boot_time, timeval* start_time) |
| : boot_time_(boot_time), start_time_(start_time) {} |
| |
| private: |
| void ThreadMain() override { GetStartTime(boot_time_, start_time_); } |
| |
| const timeval& boot_time_; |
| timeval* start_time_; |
| }; |
| |
| TEST(ProcStatReader, Threads) { |
| timespec boot_time_ts; |
| ASSERT_TRUE(GetBootTime(&boot_time_ts)); |
| timeval boot_time; |
| TimespecToTimeval(boot_time_ts, &boot_time); |
| |
| timeval main_time; |
| ASSERT_NO_FATAL_FAILURE(GetStartTime(boot_time, &main_time)); |
| |
| timeval thread_time; |
| StatTimeThread thread(boot_time, &thread_time); |
| thread.Start(); |
| ASSERT_NO_FATAL_FAILURE(thread.Join()); |
| |
| EXPECT_PRED4( |
| [](time_t main_sec, |
| suseconds_t main_usec, |
| time_t thread_sec, |
| suseconds_t thread_usec) { |
| return (thread_sec > main_sec) || |
| (thread_sec == main_sec && thread_usec >= main_usec); |
| }, |
| main_time.tv_sec, |
| main_time.tv_usec, |
| thread_time.tv_sec, |
| thread_time.tv_usec); |
| } |
| |
| } // namespace |
| } // namespace test |
| } // namespace crashpad |