Bir yöntemin yürütme süresi tam olarak milisaniye olarak nasıl kaydedilir?


222

Bir yöntemin uygulanması için ne kadar zaman gerektiğini belirlemenin bir yolu var mı (milisaniye cinsinden)?


2
Daha hızlı hale getirmek için neyi optimize edebileceğinizi öğrenmek istediğiniz için herhangi bir şans mı soruyorsunuz?
Mike Dunlavey

1
Evet, bazı sayfaları yükleyen bir UIWebView kullanıyorum. Yöntemin sayfa 1'den sayfa 10'a yüklenmesi için gereken süreyi kontrol ederek sayfa yüklemeyi optimize etmek istiyorum.
dan

2
Bu, bu sorunun bir kopyası gibi görünüyor: stackoverflow.com/questions/889380/…
Brad Larson

@BradLarson Yineleniyor gibi görünse de, diğer soru daha iyi cevaplara sahip, yani orada belirgin cevaplar (yanlış) NSDate'i kullanmayı önermiyor, bunun yerine NSDate'in bu amaç için neden yanlış yol olduğunu iyi açıklıyor.
Thomas Tempelmann

Yanıtlar:


437
NSDate *methodStart = [NSDate date];

/* ... Do whatever you need to do ... */

NSDate *methodFinish = [NSDate date];
NSTimeInterval executionTime = [methodFinish timeIntervalSinceDate:methodStart];
NSLog(@"executionTime = %f", executionTime);

Swift:

let methodStart = NSDate()

/* ... Do whatever you need to do ... */

let methodFinish = NSDate()
let executionTime = methodFinish.timeIntervalSinceDate(methodStart)
print("Execution time: \(executionTime)")

swift3:

let methodStart = Date()

/* ... Do whatever you need to do ... */

let methodFinish = Date()
let executionTime = methodFinish.timeIntervalSince(methodStart)
print("Execution time: \(executionTime)")

Kullanımı kolaydır ve milisaniyeden daha düşük bir hassasiyete sahiptir.


3
@PeterWarbo NSTimeInterval, çift kişilik bir typedef'tir ve saniye olarak tanımlanır - bkz. Developer.apple.com/library/mac/#documentation/Cocoa/Reference/…
Ben Lings

5
Bu değeri% f - NSLog ("executionTime =% f", executionTime) ile kaydedebilirsiniz;
Tony

1
NSLog(@"executionTime = %f", executionTime);
@Tony

6
Ben sadece karşılaştırdım NSDateve mach_absolute_time()30ms civarında. 27'e karşı 29, 36'ya karşı 39, 43'e karşı 45. NSDatekullanımı benim için daha kolaydı ve sonuçlar rahatsız etmeyecek kadar benzerdi mach_absolute_time().
nevan king

5
NSDate'e dayanan herhangi bir şey, geçen süreyi ölçmek için güvenli değildir, çünkü zaman geriye doğru bile atlayabilir. Buradaki diğer cevapların çoğunda gösterildiği gibi, mach_absolute_time'ı kullanmak daha güvenli bir yoldur. Bu kötü bir örnek olduğu için reddedilmelidir. Ayrıca, bunları daha ayrıntılı olarak açıklayan ilgili cevaba bakınız: stackoverflow.com/a/30363702/43615
Thomas Tempelmann

252

İşte kullandığım iki tek satır makro:

#define TICK   NSDate *startTime = [NSDate date]
#define TOCK   NSLog(@"Time: %f", -[startTime timeIntervalSinceNow])

Şöyle kullanın:

TICK;

/* ... Do Some Work Here ... */

TOCK;

13
Haha. Bunu sevdim!
bobmoff

5
Bunu bu kadar iyi yapan şey, tik takmanın o kadar unutulmaz bir ifade olduğudur ki, giriş yapmak neredeyse hiç düşünce gerektirmez.
John Riselvato

30
#define TOCK NSLog(@"%s Time: %f", __func__, -[startTime timeIntervalSinceNow])bu yanıtı da zamanlayıcının kullanıldığı işlevi döndürür. Birden fazla işlevi zamanlamak için TICK TOCK kullandığımda bunu yararlı buldum.
golmschenk

3
Harika bir fikir @ golmschenk! Ayrıca içine bakabilirsiniz __PRETTY_FUNCTION__ve __LINE__daha detaylı bilgi isterseniz.
Ron

50

OS X'te ayrıntılı zamanlama için mach_absolute_time( )beyan edilenleri kullanmalısınız <mach/mach_time.h>:

#include <mach/mach_time.h>
#include <stdint.h>

// Do some stuff to setup for timing
const uint64_t startTime = mach_absolute_time();
// Do some stuff that you want to time
const uint64_t endTime = mach_absolute_time();

// Time elapsed in Mach time units.
const uint64_t elapsedMTU = endTime - startTime;

// Get information for converting from MTU to nanoseconds
mach_timebase_info_data_t info;
if (mach_timebase_info(&info))
   handleErrorConditionIfYoureBeingCareful();

// Get elapsed time in nanoseconds:
const double elapsedNS = (double)elapsedMTU * (double)info.numer / (double)info.denom;

Tabii ki ince taneli ölçümlerle ilgili olağan uyarılar geçerlidir; Muhtemelen en iyi şekilde rutin testi birçok kez çağırmanız ve ortalama / minimum / başka bir işleme şekli almanız / almanız gerekir.

Ayrıca, Shark gibi bir araç kullanarak uygulamanızın profilini oluşturmanın daha yararlı olabileceğini lütfen unutmayın . Bu size tam zamanlama bilgisi vermez, ancak uygulamanın zamanının yüzde kaçını nerede harcandığını size söyler , bu genellikle daha yararlıdır (ancak her zaman değil).


1
Swift'te çalışmasını sağlamaya çalışıyor musunuz?
zumzum

1
"Biri sadece ... Swift dönüştürmek" - Ned Stark
stonedauwg

@zumzum Swift'te bunun bir örneği için cevabımı görün.
jbg

23

İçin uygun bir sarıcı var mach_absolute_time()- bu bir CACurrentMediaTime()işlev.

Ofsetlerin NSDateveya CFAbsoluteTimeGetCurrent()ofsetlerin aksine mach_absolute_time()ve CACurrentMediaTime()dahili ana bilgisayar saatine dayanır, kesin, monatomik bir ölçüdür ve zaman dilimleri, gün ışığından yararlanma veya artık saniye gibi harici zaman referansındaki değişikliklere tabi değildir.


objc

CFTimeInterval startTime = CACurrentMediaTime();
// Do your stuff here
CFTimeInterval endTime = CACurrentMediaTime();
NSLog(@"Total Runtime: %g s", endTime - startTime);

hızlı

let startTime = CACurrentMediaTime()
// Do your stuff here
let endTime = CACurrentMediaTime()
print("Total Runtime: \(endTime - startTime) s")

3
Bu cevabın daha fazla oyu hak ettiğini düşünüyorum. Kullanmaktan çok daha iyi NSDate.
ortalama Joe

12

Swift'te kullanıyorum:

Makrolarımda. Ekledim

var startTime = NSDate()
func TICK(){ startTime =  NSDate() }
func TOCK(function: String = __FUNCTION__, file: String = __FILE__, line: Int = __LINE__){
    println("\(function) Time: \(startTime.timeIntervalSinceNow)\nLine:\(line) File: \(file)")
}

şimdi sadece herhangi bir yeri arayabilirsin

TICK()

// your code to be tracked

TOCK()
  • Bu kod Ron'un Swift'e tercüme edilen koduna dayanıyor, kredileri var
  • Küresel düzeyde başlangıç ​​tarihi kullanıyorum, iyileştirmek için herhangi bir öneri bekliyoruz

Bu \(-startTime.timeIntervalSinceNow)(olumsuz olduğuna dikkat etmeli )
Kardan Adam

9

Bunun eski olduğunu biliyorum ama kendimi tekrar geçip dolaşırken buldum, bu yüzden burada kendi seçeneğimi sunacağımı düşündüm.

En iyi bahis, bu konudaki blog yayınımı kontrol etmektir: Objective-C'de zamanlama: Kronometre

Temel olarak, çok basit bir şekilde izlemeyi bırakan ancak kapsüllenmiş bir sınıf yazdım, böylece sadece aşağıdakileri yapmanız gerekir:

[MMStopwatchARC start:@"My Timer"];
// your work here ...
[MMStopwatchARC stop:@"My Timer"];

Ve sonunda:

MyApp[4090:15203]  -> Stopwatch: [My Timer] runtime: [0.029]

günlükte ...

Yine, biraz daha fazlası için yazıma göz atın veya buradan indirin: MMStopwatch.zip


7

Ron'un çözümüne dayalı makrolar kullanıyorum .

#define TICK(XXX) NSDate *XXX = [NSDate date]
#define TOCK(XXX) NSLog(@"%s: %f", #XXX, -[XXX timeIntervalSinceNow])

Kod satırları için:

TICK(TIME1);
/// do job here
TOCK(TIME1);

Konsolda şöyle bir şey göreceğiz: TIME1: 0.096618


Cevabınız Ron'un cevabından çok da farklı değil ve bir şekilde daha iyi ne olduğunu göremiyorum?
Trilarion

2
@ Ron'un çözümünü tek bir bağlamda iki kez kullanamazsınız. Bu makroların ana nedeni budur.
Sergey Teryokhin

4

Bu blog yazısından kod esinlenerek çok az bir sayfa sınıfı uygulama kullanın :

#import <mach/mach_time.h>

@interface DBGStopwatch : NSObject

+ (void)start:(NSString *)name;
+ (void)stop:(NSString *)name;

@end

@implementation DBGStopwatch

+ (NSMutableDictionary *)watches {
    static NSMutableDictionary *Watches = nil;
    static dispatch_once_t OnceToken;
    dispatch_once(&OnceToken, ^{
        Watches = @{}.mutableCopy;
    });
    return Watches;
}

+ (double)secondsFromMachTime:(uint64_t)time {
    mach_timebase_info_data_t timebase;
    mach_timebase_info(&timebase);
    return (double)time * (double)timebase.numer /
        (double)timebase.denom / 1e9;
}

+ (void)start:(NSString *)name {
    uint64_t begin = mach_absolute_time();
    self.watches[name] = @(begin);
}

+ (void)stop:(NSString *)name {
    uint64_t end = mach_absolute_time();
    uint64_t begin = [self.watches[name] unsignedLongLongValue];
    DDLogInfo(@"Time taken for %@ %g s",
              name, [self secondsFromMachTime:(end - begin)]);
    [self.watches removeObjectForKey:name];
}

@end

Kullanımı çok basit:

  • sadece [DBGStopwatch start:@"slow-operation"];başında ara
  • ve [DBGStopwatch stop:@"slow-operation"];bitirdikten sonra, zamanı almak için

3

Sen alabilirsiniz gerçekten bu Kronometre sınıfını kullanarak ince zamanlama (saniye seconds.parts). İPhone'daki yüksek hassasiyetli zamanlayıcıyı kullanır. NSDate'i kullanmak size yalnızca ikinci (ler) doğruluğu verecektir. Bu sürüm özellikle otomatik çalıştırma ve objektif-c için tasarlanmıştır. Gerekirse bir c ++ sürümü de var. Burada c ++ sürümünü bulabilirsiniz .

StopWatch.h

#import <Foundation/Foundation.h>


@interface StopWatch : NSObject 
{
    uint64_t _start;
    uint64_t _stop;
    uint64_t _elapsed;
}

-(void) Start;
-(void) Stop;
-(void) StopWithContext:(NSString*) context;
-(double) seconds;
-(NSString*) description;
+(StopWatch*) stopWatch;
-(StopWatch*) init;
@end

StopWatch.m

#import "StopWatch.h"
#include <mach/mach_time.h>

@implementation StopWatch

-(void) Start
{
    _stop = 0;
    _elapsed = 0;
    _start = mach_absolute_time();
}
-(void) Stop
{
    _stop = mach_absolute_time();   
    if(_stop > _start)
    {
        _elapsed = _stop - _start;
    }
    else 
    {
        _elapsed = 0;
    }
    _start = mach_absolute_time();
}

-(void) StopWithContext:(NSString*) context
{
    _stop = mach_absolute_time();   
    if(_stop > _start)
    {
        _elapsed = _stop - _start;
    }
    else 
    {
        _elapsed = 0;
    }
    NSLog([NSString stringWithFormat:@"[%@] Stopped at %f",context,[self seconds]]);

    _start = mach_absolute_time();
}


-(double) seconds
{
    if(_elapsed > 0)
    {
        uint64_t elapsedTimeNano = 0;

        mach_timebase_info_data_t timeBaseInfo;
        mach_timebase_info(&timeBaseInfo);
        elapsedTimeNano = _elapsed * timeBaseInfo.numer / timeBaseInfo.denom;
        double elapsedSeconds = elapsedTimeNano * 1.0E-9;
        return elapsedSeconds;
    }
    return 0.0;
}
-(NSString*) description
{
    return [NSString stringWithFormat:@"%f secs.",[self seconds]];
}
+(StopWatch*) stopWatch
{
    StopWatch* obj = [[[StopWatch alloc] init] autorelease];
    return obj;
}
-(StopWatch*) init
{
    [super   init];
    return self;
}

@end

Sınıf, otomatik olarak stopWatchyayımlanan bir nesneyi döndüren statik bir yönteme sahiptir.

Aradığınızda start, secondsgeçen süreyi almak için yöntemi kullanın. startYeniden başlatmak için tekrar arayın . Veya stopdurdurmak için. Çağrıyı secondsyaptıktan sonra istediğiniz zaman (çağrı ) okuyabilirsiniz stop.

Bir İşlevde Örnek (Yürütme zamanlaması çağrısı)

-(void)SomeFunc
{
   StopWatch* stopWatch = [StopWatch stopWatch];
   [stopWatch Start];

   ... do stuff

   [stopWatch StopWithContext:[NSString stringWithFormat:@"Created %d Records",[records count]]];
}

"Yalnızca saniyeler doğruluğu" yanlış. NSTimeInterval öğesinin tamamı saniyeler olsa da, bu bir çifttir.
Steven Fisher

3

Bu kodu kullanıyorum:

#import <mach/mach_time.h>

float TIME_BLOCK(NSString *key, void (^block)(void)) {
    mach_timebase_info_data_t info;
    if (mach_timebase_info(&info) != KERN_SUCCESS)
    {
        return -1.0;
    }

    uint64_t start = mach_absolute_time();
    block();
    uint64_t end = mach_absolute_time();
    uint64_t elapsed = end - start;

    uint64_t nanos = elapsed * info.numer / info.denom;
    float cost = (float)nanos / NSEC_PER_SEC;

    NSLog(@"key: %@ (%f ms)\n", key, cost * 1000);
    return cost;
}

2

Bunu kullanıyorum:

clock_t start, end;
double elapsed;
start = clock();

//Start code to time

//End code to time

end = clock();
elapsed = ((double) (end - start)) / CLOCKS_PER_SEC;
NSLog(@"Time: %f",elapsed);

Ancak iPhone'da CLOCKS_PER_SEC olduğundan emin değilim. Bırakmak isteyebilirsiniz.


2
İPhone'daki CLOCKS_PER_SEC, çılgınca yanlış bir değerdir.
mxcl

1
Bunu bildiğim iyi oldu. Bunu şimdi yapsaydım Matthew'in cevabını kullanırdım.
David Kanarek

2

mach_absolute_time()Swift 4'te kullanılan hassas zamanlama örneği :

let start = mach_absolute_time()

// do something

let elapsedMTU = mach_absolute_time() - start
var timebase = mach_timebase_info()
if mach_timebase_info(&timebase) == 0 {
    let elapsed = Double(elapsedMTU) * Double(timebase.numer) / Double(timebase.denom)
    print("render took \(elapsed)")
}
else {
    print("timebase error")
}

2

Tamam, hedefiniz daha hızlı hale getirmek için neleri düzeltebileceğinizi bulmaksa, bu biraz farklı bir hedeftir. Fonksiyonların harcadığı zamanı ölçmek, bir fark yaratıp yaratmadığınızı öğrenmek için iyi bir yoldur, ancak ne yapacağınızı bulmak için farklı bir tekniğe ihtiyacınız vardır. Tavsiye ettiğim şey bu ve iPhone'larda yapabileceğinizi biliyorum.

Edit: Reviewers Ben cevabı ayrıntılı önerdi, bu yüzden bunu söylemek için kısa bir yol düşünmeye çalışıyorum.
Genel programınız sizi rahatsız etmek için yeterli zaman alır. Diyelim ki N saniye.
Hızlandırabileceğinizi varsayıyorsunuz. Bunu yapabilmenin tek yolu, o anda yaptığı bir şeyi yapmamasını sağlamak, m saniye hesaplamaktır .
Başlangıçta bu şeyin ne olduğunu bilmiyorsunuz. Tüm programcıların yaptığı gibi tahmin edebilirsiniz, ancak kolayca başka bir şey olabilir. Her neyse, onu nasıl bulacağınız aşağıda açıklanmıştır:

O şey, ne olursa olsun , zamanın m / N'sini açıklar, bu da rastgele duraklarsanız, m / N olma olasılığını o şeyi yapma eyleminde yakalayacağınız anlamına gelir . Tabii ki başka bir şey yapıyor olabilir, ama duraklatın ve ne yaptığını görün.
Şimdi tekrar yap. Aynı şeyi tekrar yaptığını görürseniz, daha şüpheli olabilirsiniz.

10 kez veya 20 yapın. Şimdi birden fazla duraklamada belirli bir şey yaptığını görüyorsanız (nasıl tarif ederseniz yapın), kurtulabileceğiniz iki şey biliyorsunuz. Kabaca ne kadar zaman aldığını çok iyi biliyorsunuz, ama tam olarak neyi düzelteceğinizi biliyorsunuz .
Ayrıca tam olarak ne kadar zaman kazanacağınızı bilmek istiyorsanız , bu kolay. Önce ölçün, düzeltin ve sonra ölçün. Gerçekten hayal kırıklığına uğradıysanız, düzeltmeyi geri alın.

Bunun ölçümden ne kadar farklı olduğunu görüyor musunuz? Bu oluyor ölçme değil bulma . Çoğu profil oluşturma, bu kadar önemli bir zamanın ne kadar sürdüğünü tam olarak ölçmeye dayanır ve neyin düzeltilmesi gerektiğini belirleme sorununu elle dalgalandırır. Profil oluşturma her sorunu bulamaz, ancak bu yöntem her sorunu bulur ve size zarar veren bulamadığınız problemlerdir.


0

Swift'te defer anahtar sözcüğünü kullanarak bunu yapmanın başka bir yolu

func methodName() {
  let methodStart = Date()
  defer {
    let executionTime = Date().timeIntervalSince(methodStart)
    print("Execution time: \(executionTime)")
  }
  // do your stuff here
}

Apple'ın dokümanlarından : Program denetimini, erteleme ifadesinin göründüğü kapsamın dışına aktarmadan hemen önce kodun yürütülmesi için bir erteleme ifadesi kullanılır.

Bu, ilgili kodun gruplandırılması avantajı ile bir dene / sonla bloğuna benzer.


0

Bunu utils kütüphanemde kullanıyorum ( Swift 4.2 ):

public class PrintTimer {
    let start = Date()
    let name: String

    public init(file: String=#file, line: Int=#line, function: String=#function, name: String?=nil) {
        let file = file.split(separator: "/").last!
        self.name = name ?? "\(file):\(line) - \(function)"
    }

    public func done() {
        let end = Date()
        print("\(self.name) took \((end.timeIntervalSinceReferenceDate - self.start.timeIntervalSinceReferenceDate).roundToSigFigs(5)) s.")
    }
}

... sonra şöyle bir yöntem çağırın:

func myFunctionCall() {
    let timer = PrintTimer()
    // ...
    timer.done()
}

... çalıştırdıktan sonra konsolda şöyle görünür:

MyFile.swift:225 - myFunctionCall() took 1.8623 s.

Yukarıdaki TICK / TOCK kadar özlü değildir, ancak ne yaptığını görmek için yeterince açıktır ve zamanlananı otomatik olarak içerir (dosyaya, yöntemin başlangıcındaki satır ve işlev adına göre). Açıkçası ben daha fazla ayrıntı istedim (ex, ben sadece olağan durumda olduğu gibi bir yöntem çağrısı zamanlama değil, bunun yerine bu yöntem içinde bir blok zamanlama) PrintTimer init "name =" Foo "" parametresini ekleyebilirsiniz varsayılanların yanında bir ad vermek için.


-1

Bir UIWebView içinde bir sayfadan diğerine geçiş süresini optimize etmek istediğiniz için, bu sayfaları yüklemek için kullanılan Javascript'i gerçekten optimize etmek istediğiniz anlamına gelmiyor mu?

Bu amaçla, burada bahsettiğim gibi bir WebKit profiline bakardım:

http://www.alertdebugging.com/2009/04/29/building-a-better-javascript-profiler-with-webkit/

Başka bir yaklaşım, yüksek düzeyde başlamak ve her seferinde tüm web görünümünü yenilemek yerine AJAX tarzı sayfa yüklemesini kullanarak yükleme sürelerini en aza indirmek için söz konusu web sayfalarını nasıl tasarlayabileceğinizi düşünmek olacaktır.


-1
struct TIME {

    static var ti = mach_timebase_info()
    static var k: Double = 1
    static var mach_stamp: Double {

        if ti.denom == 0 {
            mach_timebase_info(&ti)
            k = Double(ti.numer) / Double(ti.denom) * 1e-6
        }
        return Double(mach_absolute_time()) * k
    }
    static var stamp: Double { return NSDate.timeIntervalSinceReferenceDate() * 1000 }
}

do {
    let mach_start = TIME.mach_stamp
    usleep(200000)
    let mach_diff = TIME.mach_stamp - mach_start

    let start = TIME.stamp
    usleep(200000)
    let diff = TIME.stamp - start

    print(mach_diff, diff)
}

-1

İşte uzun süre çalışan bir süreç bulmak için her yerde kodu ikiye bölmek için bir Swift 3 çözümü.

var increment: Int = 0

var incrementTime = NSDate()

struct Instrumentation {
    var title: String
    var point: Int
    var elapsedTime: Double

    init(_ title: String, _ point: Int, _ elapsedTime: Double) {
        self.title = title
        self.point = point
        self.elapsedTime = elapsedTime
    }
}

var elapsedTimes = [Instrumentation]()

func instrument(_ title: String) {
    increment += 1
    let incrementedTime = -incrementTime.timeIntervalSinceNow
    let newPoint = Instrumentation(title, increment, incrementedTime)
    elapsedTimes.append(newPoint)
    incrementTime = NSDate()
}

Kullanım: -

instrument("View Did Appear")

print("ELAPSED TIMES \(elapsedTimes)")

Örnek çıktı: -

ELAPSED TIMES [MyApp.SomeViewController.Instrumentation (başlık: "View View Load Load", nokta: 1, geçenSaat: 0.040504038333892822), MyApp.SomeViewController.Instrumentation (başlık: "Alt Görüntüleme Ekleme Tamamlandı", nokta: 2, elaSedTime: 0.0105805175, 0,0107212517) MyApp.SomeViewController.Instrumentation (başlık: "Görünüm Göründü", nokta: 3, geçenSaat: 0.56564098596572876)]


-1

birçok cevap gariptir ve gerçekten milisaniye olarak sonuç vermez (ancak saniyeler içinde veya başka bir şeyle):

MS (MILLISECONDS) almak için kullandığım burada:

Swift:

let startTime = NSDate().timeIntervalSince1970 * 1000

// your Swift code

let endTimeMinusStartTime = NSDate().timeIntervalSince1970 * 1000 - startTime
print("time code execution \(endTimeMinStartTime) ms")

Objective-C:

double startTime = [[NSDate date] timeIntervalSince1970] * 1000.0;

// your Objective-C code

double endTimeMinusStartTime = [[NSDate date] timeIntervalSince1970] * 1000.0 - startTime;
printf("time code execution %f ms\n", endTimeMinusStartTime );

-1

Swift 4 için sınıfınıza Temsilci olarak ekleyin:

public protocol TimingDelegate: class {
    var _TICK: Date?{ get set }
}

extension TimingDelegate {
    var TICK: Date {
        _TICK = Date()
        return(_TICK)!
     }

    func TOCK(message: String)  {

        if (_TICK == nil){
            print("Call 'TICK' first!")
        }

        if (message == ""){
            print("\(Date().timeIntervalSince(_TICK!))")
        }
        else{
            print("\(message): \(Date().timeIntervalSince(_TICK!))")
        }
    }
}

Sınıfımıza ekleyin:

class MyViewcontroller: UIViewController, TimingDelegate

Ardından sınıfınıza ekleyin:

var _TICK: Date?

Bir şeyi zamanlamak istediğinizde şunlarla başlayın:

TICK

Ve şununla bit:

TOCK("Timing the XXX routine")

Cevapları ve yorumları okudunuz mu? Bunun için Tarih kullanmayın!
mat
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.