2 * Copyright (c) 2017 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
30 #include <uuid/uuid.h>
36 #include <sys/param.h>
37 #include <sys/sysctl.h>
38 #include <sys/resource.h>
39 #include <sys/types.h>
43 #include <mach/mach.h>
44 #include <mach/machine.h>
45 #include <mach/mach_time.h>
46 #include <mach-o/loader.h>
47 #include <mach-o/nlist.h>
48 #include <mach-o/fat.h>
50 #include <libc_private.h>
52 #include "Diagnostics.h"
54 #if BUILDING_CACHE_BUILDER
55 #include <dispatch/dispatch.h>
56 dispatch_queue_t sWarningQueue
= dispatch_queue_create("com.apple.dyld.cache-builder.warnings", NULL
);
59 Diagnostics
::Diagnostics(bool verbose
)
60 #if BUILDING_CACHE_BUILDER
67 #if BUILDING_CACHE_BUILDER
68 Diagnostics
::Diagnostics(const std
::string
& prefix
, bool verbose
)
75 Diagnostics
::~Diagnostics()
80 void Diagnostics
::error(const char* format
, ...)
83 va_start(list
, format
);
88 void Diagnostics
::error(const char* format
, va_list list
)
90 //FIXME: this should be assertNoError(), but we currently overwrite some errors
92 _buffer
= _simple_salloc();
93 _simple_vsprintf(_buffer
, format
, list
);
95 #if BUILDING_CACHE_BUILDER
99 if (_prefix
.empty()) {
100 fprintf(stderr
, "%s\n", _simple_string(_buffer
));
102 fprintf(stderr
, "[%s] %s\n", _prefix
.c_str(), _simple_string(_buffer
));
107 bool Diagnostics
::hasError() const
109 return _buffer
!= nullptr;
112 bool Diagnostics
::noError() const
114 return _buffer
== nullptr;
117 void Diagnostics
::clearError()
120 _simple_sfree(_buffer
);
124 void Diagnostics
::assertNoError() const
126 if ( _buffer
!= nullptr )
127 abort_report_np("%s", _simple_string(_buffer
));
130 bool Diagnostics
::errorMessageContains(const char* subString
) const
132 if ( _buffer
== nullptr )
134 return (strstr(_simple_string(_buffer
), subString
) != nullptr);
138 #if !BUILDING_CACHE_BUILDER
139 const char* Diagnostics
::errorMessage() const
141 return _simple_string(_buffer
);
145 void Diagnostics
::warning(const char* format
, ...)
147 _SIMPLE_STRING tmp
= _simple_salloc();
149 va_start(list
, format
);
150 _simple_vsprintf(tmp
, format
, list
);
152 #if BUILDING_CACHE_BUILDER
153 dispatch_sync(sWarningQueue
, ^{
154 _warnings
.insert(_simple_string(tmp
));
157 _warnings
.insert(_simple_string(tmp
));
162 void Diagnostics
::verbose(const char* format
, ...)
169 va_start(list
, format
);
170 vasprintf(&output_string
, format
, list
);
173 if (_prefix
.empty()) {
174 fprintf(stderr
, "%s", output_string
);
176 fprintf(stderr
, "[%s] %s", _prefix
.c_str(), output_string
);
181 const std
::string Diagnostics
::prefix() const
186 void Diagnostics
::copy(const Diagnostics
& other
)
188 if ( other
.hasError() )
189 error("%s", other
.errorMessage().c_str());
190 for (const std
::string
& warn
: other
.warnings())
191 warning("%s", warn
.c_str());
194 std
::string Diagnostics
::errorMessage() const
196 if ( _buffer
!= nullptr )
197 return _simple_string(_buffer
);
202 const std
::set
<std
::string
> Diagnostics
::warnings() const
204 #if BUILDING_CACHE_BUILDER
205 __block std
::set
<std
::string
> retval
;
206 dispatch_sync(sWarningQueue
, ^{
215 void Diagnostics
::clearWarnings()
217 #if BUILDING_CACHE_BUILDER
218 dispatch_sync(sWarningQueue
, ^{
226 #if BUILDING_CACHE_BUILDER
227 void TimeRecorder
::pushTimedSection() {
228 openTimings
.push_back(mach_absolute_time());
231 void TimeRecorder
::recordTime(const char* format
, ...) {
232 uint64_t t
= mach_absolute_time();
233 uint64_t previousTime
= openTimings
.back();
234 openTimings
.pop_back();
236 char* output_string
= nullptr;
238 va_start(list
, format
);
239 vasprintf(&output_string
, format
, list
);
242 if (output_string
!= nullptr) {
243 timings
.push_back(TimingEntry
{
244 .time
= t
- previousTime
,
245 .logMessage
= std
::string(output_string
),
246 .depth
= (int)openTimings
.size()
250 openTimings
.push_back(mach_absolute_time());
253 void TimeRecorder
::popTimedSection() {
254 openTimings
.pop_back();
257 static inline uint32_t absolutetime_to_milliseconds(uint64_t abstime
)
259 return (uint32_t)(abstime
/1000/1000);
262 void TimeRecorder
::logTimings() {
263 for (const TimingEntry
& entry
: timings
) {
264 for (int i
= 0 ; i
< entry
.depth
; i
++) {
267 std
::cerr
<< "time to " << entry
.logMessage
<< " " << absolutetime_to_milliseconds(entry
.time
) << "ms" << std
::endl
;