In my app I have a logger that writes errors and status messages to a string. It's not written to a file, it's just handy to have something to look at when a bug happens without an attached debug session.
The addLog() method is called approx. 0-10 times every 3 seconds and is fairly simple:
every call adds the new addition to the beginning of the string along with the second it has happened
to prevent the string from blowing up in terms of size, if it exceeds 2kb, it will successively cut the "oldest" 100 log characters until it's smaller than 2kb again
The code looks as following:
var logString = ""
func addLog(s : String){
let date = Date()
logString = "\(date.second)\(s).\n\(logString)"
while(logString.count>2000){
logString=String(logString.dropLast(100))
}
}
I've never seen anything wrong with it until today when I received a crash log:
Thread 5 name:
Thread 5 Crashed:
0 libsystem_kernel.dylib 0x00000001c00f5414 __pthread_kill + 8
1 libsystem_pthread.dylib 0x00000001ddc50b50 pthread_kill + 272 (pthread.c:1392)
2 libsystem_c.dylib 0x000000019b5d3b74 abort + 104 (abort.c:110)
3 libsystem_malloc.dylib 0x00000001a1faf49c malloc_vreport + 560 (malloc_printf.c:183)
4 libsystem_malloc.dylib 0x00000001a1faf740 malloc_zone_error + 104 (malloc_printf.c:219)
5 libsystem_malloc.dylib 0x00000001a1f99ed8 free_small_botch + 40 (magazine_small.c:2215)
6 libswiftCore.dylib 0x00000001961103d8 _swift_release_dealloc + 40 (HeapObject.cpp:648)
7 APPNAME 0x00000001046b56a0 AppDelegate.addLog(s:) + 960 (AppDelegate.swift:0)
What's weird about the log itself is that the addLog() function is not in line 0 of my AppDelegate but maybe that's normal to have the wrong line in the crash report.
The only possible explanation for this issue that I can come up with is that there is an issue with thread safety in my function, or that I have missed something regarding the garbage collection in swift. It's very likely that the function is called from different threads at the same time, could that be an issue? Or do I have to get into the objective-c times retain etc. again to resolve this? What can I make out of this crash log?
You must handle all changes in serial queue. The simple modification:
private let queue = DispatchQueue(label: "addlog.queue")
private var logString = ""
func addLog(s : String) {
queue.async { [weak self] in
guard let self = self else { return }
let date = Date()
self.logString = String("\(date.second)\(s).\n\(self.logString)".prefix(2000))
}
}
In your case you can read and write the "logString" parameter from different threads, using serial DispatchQueue for handle all actions with parameter make unavailable to read and write parameter at one moment of time
Related
Right now it seems that on every click tick, the running process is preempted and forced to yield the processor, I have thoroughly investigated the code-base and the only relevant part of the code to process preemption is below (in trap.c):
// Force process to give up CPU on clock tick.
// If interrupts were on while locks held, would need to check nlock.
if(myproc() && myproc() -> state == RUNNING && tf -> trapno == T_IRQ0 + IRQ_TIMER)
yield();
I guess that timing is specified in T_IRQ0 + IRQ_TIMER, but I can't figure out how these two can be modified, these two are specified in trap.h:
#define T_IRQ0 32 // IRQ 0 corresponds to int T_IRQ
#define IRQ_TIMER 0
I wonder how I can change the default RR scheduling time-slice (which is right now 1 clock tick, fir example make it 10 clock-tick)?
If you want a process to be executed more time than the others, you can allow it more timeslices, *without` changing the timeslice duration.
To do so, you can add some extra_slice and current_slice in struct proc and modify the TIMER trap handler this way:
if(myproc() && myproc()->state == RUNNING &&
tf->trapno == T_IRQ0+IRQ_TIMER)
{
int current = myproc()->current_slice;
if ( current )
myproc()->current_slice = current - 1;
else
yield();
}
Then you just have to create a syscall to set extra_slice and modify the scheduler function to reset current_slice to extra_slice at process wakeup:
// Switch to chosen process. It is the process's job
// to release ptable.lock and then reacquire it
// before jumping back to us.
c->proc = p;
switchuvm(p);
p->state = RUNNING;
p->current_slice = p->extra_slice
You can read lapic.c file:
lapicinit(void)
{
....
// The timer repeatedly counts down at bus frequency
// from lapic[TICR] and then issues an interrupt.
// If xv6 cared more about precise timekeeping,
// TICR would be calibrated using an external time source.
lapicw(TDCR, X1);
lapicw(TIMER, PERIODIC | (T_IRQ0 + IRQ_TIMER));
lapicw(TICR, 10000000);
So, if you want the timer interrupt to be more spaced, change the TICR value:
lapicw(TICR, 10000000); //10 000 000
can become
lapicw(TICR, 100000000); //100 000 000
Warning, TICR references a 32bits unsigned counter, do not go over 4 294 967 295 (0xFFFFFFFF)
I've got a code which must be executed every half a second and I'm using the Xcode playground. I used this top answer and got a code like this:
for (index, item) in array.enumerated() {
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(index), execute: {
print("\(index) - \(df.string(from: Date()))"
//play sound every second
})
}
This code is executed every second (I know that I have to divide it by 2 to get half a second but wanted to see the results). I used the DateFormatter to figure out times because I couldn't figure out why sounds are not played evenly.
let df = DateFormatter()
df.dateFormat = "ss.SSSS"
The result is that it is not triggered exactly every 1 second.
0 - 17.4800
1 - 18.5770 // even though it's not called exactly after 1s it's acceptable
2 - 19.6750
3 - 20.7770
4 - 21.8780
5 - 22.9760
6 - 24.0710
7 - 25.1690
8 - 26.2720
9 - 27.3640
10 - 28.4760
11 - 28.7580 //0.3s of difference
12 - 30.4800
13 - 30.5060 // 0.1s of difference
14 - 32.4800
15 - 32.5030 // less than 0.1s of difference
Here you execute your Print statement asynchronous so you do not get your printed data after half a second(or one second).If you execute it synchronously then you get your printed data 1 second interval.To know more about dispatch queue follow this link.Let me know if you have any problem.
I'm trying to figure out Marathon's exponential backoff configuration. Here's the documentation:
The backoffSeconds and backoffFactor values are multiplied until they reach the maxLaunchDelaySeconds value. After they reach that value, Marathon waits maxLaunchDelaySeconds before repeating this cycle exponentially. For example, if backoffSeconds: 3, backoffFactor: 2, and maxLaunchDelaySeconds: 3600, there will be ten attempts to launch a failed task, each three seconds apart. After these ten attempts, Marathon will wait 3600 seconds before repeating this cycle.
The way I think of exponential backoff is that the wait periods should be:
3*2^0 = 3
3*2^1 = 6
3*2^2 = 12
3*2^3 = 24 and so on
so every time the app crashes, Marathon will wait a longer period of time before retrying. However, given the description above, Marathon's logic for waiting looks something like this:
int retryCount = 0;
while(backoffSeconds * (backoffFactor ^ retryCount) < maxLaunchDelaySeconds)
{
wait(backoffSeconds);
retryCount++;
}
wait(maxLaunchDelaySeconds);
This matches the explanation in the documentation, since 3*2^x < 3600 for values of x fewer than or equal to 10. However, I really don't see how it can be called an exponential backoff, since the wait time is constant.
Is there a way to make Marathon wait progressively longer times with every restart of the app? Am I misunderstand the doc? Any help would be appreciated!
as far as I understand the code in the RateLimiter.scala, it is like you described, but then capped to the maxLaunchDelay waiting period. Let`s say maxLaunchDelay is one hour (3600s)
3*2^0 = 3
3*2^1 = 6
3*2^2 = 12
3*2^3 = 24
3*2^4 = 48
3*2^5 = 96
3*2^6 = 192
3*2^7 = 384
3*2^8 = 768
3*2^9 = 1536
3*2^10 = 3072
3*2^11 = 3600 (6144)
3*2^12 = 3600 (12288)
3*2^13 = 3600 (24576)
Which brings us a typically 2^n graph, see
You would get a bigger increase, if you would other backoffFactors,
for example backoff factor 10:
or backoff factor 20:
Additionally I saw a re-work of this topic, code review currently open here: https://phabricator.mesosphere.com/D1007
What do you think?
Thanks
Johannes
The Java docs say the following:
Emit the last value from this Flux only if there were no new values emitted during the time window provided by a publisher for that particular last value.
However I found the above description confusing. I read in gitter chat that its similar to debounce in RxJava. Can someone please illustrate it with an example? I could not find this anywhere after doing a thorough search.
sampleTimeout lets you associate a companion Flux X' to each incoming value x in the source. If X' completes before the next value is emitted in the source, then value x is emitted. If not, x is dropped.
The same processing is applied to subsequent values.
Think of it as splitting the original sequence into windows delimited by the start and completion of each companion flux. If two windows overlap, the value that triggered the first one is dropped.
On the other side, you have sample(Duration) which only deals with a single companion Flux. It splits the sequence into windows that are contiguous, at a regular time period, and drops all but the last element emitted during a particular window.
(edit): about your use case
If I understand correctly, it looks like you have a processing of varying length that you want to schedule periodically, but you also don't want to consider values for which processing takes more than one period?
If so, it sounds like you want to 1) isolate your processing in its own thread using publishOn and 2) simply need sample(Duration) for the second part of the requirement (the delay allocated to a task is not changing).
Something like this:
List<Long> passed =
//regular scheduling:
Flux.interval(Duration.ofMillis(200))
//this is only to show that processing is indeed started regularly
.elapsed()
//this is to isolate the blocking processing
.publishOn(Schedulers.elastic())
//blocking processing itself
.map(tuple -> {
long l = tuple.getT2();
int sleep = l % 2 == 0 || l % 5 == 0 ? 100 : 210;
System.out.println(tuple.getT1() + "ms later - " + tuple.getT2() + ": sleeping for " + sleep + "ms");
try {
Thread.sleep(sleep);
} catch (InterruptedException e) {
e.printStackTrace();
}
return l;
})
//this is where we say "drop if too long"
.sample(Duration.ofMillis(200))
//the rest is to make it finite and print the processed values that passed
.take(10)
.collectList()
.block();
System.out.println(passed);
Which outputs:
205ms later - 0: sleeping for 100ms
201ms later - 1: sleeping for 210ms
200ms later - 2: sleeping for 100ms
199ms later - 3: sleeping for 210ms
201ms later - 4: sleeping for 100ms
200ms later - 5: sleeping for 100ms
201ms later - 6: sleeping for 100ms
196ms later - 7: sleeping for 210ms
204ms later - 8: sleeping for 100ms
198ms later - 9: sleeping for 210ms
201ms later - 10: sleeping for 100ms
196ms later - 11: sleeping for 210ms
200ms later - 12: sleeping for 100ms
202ms later - 13: sleeping for 210ms
202ms later - 14: sleeping for 100ms
200ms later - 15: sleeping for 100ms
[0, 2, 4, 5, 6, 8, 10, 12, 14, 15]
So the blocking processing is triggered approximately every 200ms, and only values that where processed within 200ms are kept.
I am currently trying to learn swift and while I was coding some dummy stuff, I noticed the xcode is skipping some lines and sometimes stops on weird lines . my env: macos sierra,xcode Version 8.2.1 (8C1002)
since xcode is skipping some lines , I thought the problem is from code optimisation , then I switched to terminal to debug, below is the input&output
I compiled using
swiftc -g -Onone *.swift
then
load it with lldb
lldb main
set breakpoint on lint 18 as shown below and process run with "r"
17 do {
-> 18 try StaticM.teststatic2()
19 print (1)
20 }catch {
21
(lldb) thread step-in
Process 963 stopped
* thread #1: tid = 0x86e1, 0x0000000100001f6a main`static StaticM.teststatic2(self=main.StaticM, $error=Error # 0x00007fff5fbffac0) throws -> () + 26 at staticExt.swift:13, queue = 'com.apple.main-thread', stop reason = step in
frame #0: 0x0000000100001f6a main`static StaticM.teststatic2(self=main.StaticM, $error=Error # 0x00007fff5fbffac0) throws -> () + 26 at staticExt.swift:13
10 public extension StaticM {
11 #discardableResult
12 public static func teststatic2() throws {
-> 13 var asdf=2;
14 let sdfgsdfg=2;
15 print(sdfgsdfg);
16 print (asdf);
(lldb) n
Process 963 stopped
* thread #1: tid = 0x86e1, 0x0000000100001f72 main`static StaticM.teststatic2(self=main.StaticM, $error=Error # 0x00007fff5fbffac0) throws -> () + 34 at staticExt.swift:15, queue = 'com.apple.main-thread', stop reason = step over
frame #0: 0x0000000100001f72 main`static StaticM.teststatic2(self=main.StaticM, $error=Error # 0x00007fff5fbffac0) throws -> () + 34 at staticExt.swift:15
12 public static func teststatic2() throws {
13 var asdf=2;
14 let sdfgsdfg=2;
-> 15 print(sdfgsdfg);
16 print (asdf);
17 asdf += 1;
18 }
(lldb) process continue
Process 963 resuming
2
2
1
Process 963 exited with status = 0 (0x00000000)
(lldb)
question is , after I go to next line using "n" in lldb, why lldb skips line 14 of staticExt.swift and jumps straight to line 15 ?
also , sometimes when trying to debug some other program, I click on "step-in" in xcode, it stops on the declaration line of the func instead of first line in the code block, I clicked stepover , it goes back to the caller func line instead of executing the first line of that func.
in all,programe works , but why lldb jumps even with -Onone and -g ?
could you please let me where can I find more info ?
thank you very much.
Swift's basic types (Int's, Strings, etc.) are formally somewhat heavy-weight - for instance in your example:
(lldb) expr --raw -- asdf
(Swift.Int) $R0 = {
_value = 3
}
To make performance acceptable even though this is true, the swift compiler "unboxes" these types in common operations and applies other "optimization-like" tricks to make all this go faster. Since this is such a pervasive feature of swift, it does so even at -Onone, to make performance of unoptimized code acceptable. And once the optimizer starts getting involved, it sometimes can't help itself and will do more work than maybe it should at -Onone.
In this case, because the first variable is a "let" of an Int, swiftc knows it can just directly insert the value into the arguments when it goes to call print, so it doesn't need to make up a variable. If you change the let to a var then code will actually be generated for that line, and the line will get its own line table entry.
If you know how to read assembly code, you can look at the mixed disassembly to see this in action.
In lldb:
(lldb) dis -m -f
will give you mixed disassembly of the current frame.