View in English

  • Apple Developer
    • Get Started

    Explore Get Started

    • Overview
    • Learn
    • Apple Developer Program

    Stay Updated

    • Latest News
    • Hello Developer
    • Platforms

    Explore Platforms

    • Apple Platforms
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    Featured

    • Design
    • Distribution
    • Games
    • Accessories
    • Web
    • Home
    • CarPlay
    • Technologies

    Explore Technologies

    • Overview
    • Xcode
    • Swift
    • SwiftUI

    Featured

    • Accessibility
    • App Intents
    • Apple Intelligence
    • Games
    • Machine Learning & AI
    • Security
    • Xcode Cloud
    • Community

    Explore Community

    • Overview
    • Meet with Apple events
    • Community-driven events
    • Developer Forums
    • Open Source

    Featured

    • WWDC
    • Swift Student Challenge
    • Developer Stories
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Centers
    • Documentation

    Explore Documentation

    • Documentation Library
    • Technology Overviews
    • Sample Code
    • Human Interface Guidelines
    • Videos

    Release Notes

    • Featured Updates
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • Downloads

    Explore Downloads

    • All Downloads
    • Operating Systems
    • Applications
    • Design Resources

    Featured

    • Xcode
    • TestFlight
    • Fonts
    • SF Symbols
    • Icon Composer
    • Support

    Explore Support

    • Overview
    • Help Guides
    • Developer Forums
    • Feedback Assistant
    • Contact Us

    Featured

    • Account Help
    • App Review Guidelines
    • App Store Connect Help
    • Upcoming Requirements
    • Agreements and Guidelines
    • System Status
  • Quick Links

    • Events
    • News
    • Forums
    • Sample Code
    • Videos
 

Vidéos

Ouvrir le menu Fermer le menu
  • Collections
  • Toutes les vidéos
  • À propos

Plus de vidéos

  • À propos
  • Résumé
  • Code
  • Optimiser les performances du processeur avec Instruments

    Découvrez comment optimiser votre app pour les puces Apple à l'aide de deux nouveaux outils d'assistance matérielle dans Instruments. Nous commencerons par expliquer comment profiler votre app, puis nous approfondirons en montrant chaque fonction appelée avec Processor Trace. Nous verrons également comment utiliser les modes Compteurs de processeur pour analyser votre code à la recherche de goulots d'étranglement du processeur.

    Chapitres

    • 0:00 - Introduction et ordre du jour
    • 2:28 - État d’esprit de performance
    • 8:50 - Profileurs
    • 13:20 - Étendue
    • 14:05 - Processor Trace
    • 19:51 - Analyse des goulots d’étranglement
    • 31:33 - Récapitulatif
    • 32:13 - Étapes suivantes

    Ressources

    • Performance and metrics
    • Analyzing CPU usage with the Processor Trace instrument
    • Apple Silicon CPU Optimization Guide Version 4
    • Tuning your code’s performance for Apple silicon
      • Vidéo HD
      • Vidéo SD

    Vidéos connexes

    WWDC25

    • Améliorer l’utilisation de la mémoire et les performances avec Swift
    • Optimiser les performances de SwiftUI avec Instruments
    • Profilez et optimisez la consommation d’énergie de votre app

    WWDC24

    • Explore Swift performance

    WWDC23

    • Analyze hangs with Instruments

    WWDC22

    • Visualize and optimize Swift concurrency
  • Rechercher dans cette vidéo…
    • 6:37 - Binary search in Collection

      public func binarySearch<E, C>(
          needle: E,
          haystack: C
      ) -> C.Index where E: Comparable, C: Collection<E> {
          var start = haystack.startIndex
          var length = haystack.count
      
          while length > 0 {
              let half = length / 2
              let middle = haystack.index(start, offsetBy: half)
              let middleValue = haystack[middle]
              if needle < middleValue {
                  length = half
              } else if needle == middleValue {
                  return middle
              } else {
                  start = haystack.index(after: middle)
                  length -= half + 1
              }
          }
      
          return start
      }
    • 7:49 - Throughput benchmark

      import Testing
      import OSLog
      
      let signposter = OSSignposter(
          subsystem: "com.example.apple-samplecode.MyBinarySearch",
          category: .pointsOfInterest
      )
      
      func search(
          name: StaticString,
          duration: Duration,
          _ search: () -> Void
      ) {
          var now = ContinuousClock.now
          var outerIterations = 0
          
          let interval = signposter.beginInterval(name)
          let start = ContinuousClock.now
          repeat {
              search()
              outerIterations += 1
              now = .now
          } while (start.duration(to: now) < duration)
          let elapsed = start.duration(to: now)
          let seconds = Double(elapsed.components.seconds) +
                  Double(elapsed.components.attoseconds) / 1e18
          let throughput = Double(outerIterations) / seconds
          signposter.endInterval(name, interval, "\(throughput) ops/s")
          print("\(name): \(throughput) ops/s")
      }
      
      let arraySize = 8 << 20
      let arrayCount = arraySize / MemoryLayout<Int>.size
      let searchCount = 10_000
      
      struct MyBinarySearchTests {
          let sortedArray: [Int]
          let randomElements: [Int]
          
          init() {
              let sortedArray: [Int] = (0..<arrayCount).map { _ in
                      .random(in: 0..<arrayCount)
              }.sorted()
              self.randomElements = (0..<searchCount).map { _ in
                  sortedArray.randomElement()!
              }
              self.sortedArray = sortedArray
          }
      
          @Test func searchCollection() throws {
              search(name: "Collection", duration: .seconds(1)) {
                  for element in randomElements {
                      _ = binarySearch(needle: element, haystack: sortedArray)
                  }
              }
          }
      }
    • 13:46 - Binary search in Span

      public func binarySearch<E: Comparable>(
          needle: E,
          haystack: Span<E>
      ) -> Span<E>.Index {
          var start = haystack.indices.startIndex
          var length = haystack.count
      
          while length > 0 {
              let half = length / 2
              let middle = haystack.indices.index(start, offsetBy: half)
              let middleValue = haystack[middle]
              if needle < middleValue {
                  length = half
              } else if needle == middleValue {
                  return middle
              } else {
                  start = haystack.indices.index(after: middle)
                  length -= half + 1
              }
          }
      
          return start
      }
    • 15:09 - Throughput benchmark for binary search in Span

      extension MyBinarySearchTests {
          @Test func searchSpan() throws {
              let span = sortedArray.span
              search(name: "Span", duration: .seconds(1)) {
                  for element in randomElements {
                      _ = binarySearch(needle: element, haystack: span)
                  }
              }
          }
      
          @Test func searchSpanForProcessorTrace() throws {
              let span = sortedArray.span
              signposter.withIntervalSignpost("Span") {
                  for element in randomElements[0..<10] {
                      _ = binarySearch(needle: element, haystack: span)
                  }
              }
          }
      }
    • 19:17 - Binary search in Span

      public func binarySearchInt(
          needle: Int,
          haystack: Span<Int>
      ) -> Span<Int>.Index {
          var start = haystack.indices.startIndex
          var length = haystack.count
      
          while length > 0 {
              let half = length / 2
              let middle = haystack.indices.index(start, offsetBy: half)
              let middleValue = haystack[middle]
              if needle < middleValue {
                  length = half
              } else if needle == middleValue {
                  return middle
              } else {
                  start = haystack.indices.index(after: middle)
                  length -= half + 1
              }
          }
          return start
      }
    • 23:04 - Throughput benchmark for binary search in Span

      extension MyBinarySearchTests {
          @Test func searchSpanInt() throws {
              let span = sortedArray.span
              search(name: "Span<Int>", duration: .seconds(1)) {
                  for element in randomElements {
                      _ = binarySearchInt(needle: element, haystack: span)
                  }
              }
          }
      }
    • 26:34 - Branchless binary search

      public func binarySearchBranchless(
          needle: Int,
          haystack: Span<Int>
      ) -> Span<Int>.Index {
          var start = haystack.indices.startIndex
          var length = haystack.count
      
          while length > 0 {
              let remainder = length % 2
              length /= 2
              let middle = start &+ length
              let middleValue = haystack[middle]
              if needle > middleValue {
                  start = middle &+ remainder
              }
          }
      
          return start
      }
    • 27:20 - Throughput benchmark for branchless binary search

      extension MyBinarySearchTests {
          @Test func searchBranchless() throws {
              let span = sortedArray.span
              search(name: "Branchless", duration: .seconds(1)) {
                  for element in randomElements {
                      _ = binarySearchBranchless(needle: element, haystack: span)
                  }
              }
          }
      }
    • 29:27 - Eytzinger binary search

      public func binarySearchEytzinger(
          needle: Int,
          haystack: Span<Int>
      ) -> Span<Int>.Index {
          var start = haystack.indices.startIndex.advanced(by: 1)
          let length = haystack.count
      
          while start < length {
              let value = haystack[start]
              start *= 2
              if value < needle {
                  start += 1
              }
          }
          
          return start >> ((~start).trailingZeroBitCount + 1)
      }
    • 30:34 - Throughput benchmark for Eytzinger binary search

      struct MyBinarySearchEytzingerTests {
          let eytzingerArray: [Int]
          let randomElements: [Int]
      
          static func reorderEytzinger(_ input: [Int], array: inout [Int], sourceIndex: Int, resultIndex: Int) -> Int {
              var sourceIndex = sourceIndex
              if resultIndex < array.count {
                  sourceIndex = reorderEytzinger(input, array: &array, sourceIndex: sourceIndex, resultIndex: 2 * resultIndex)
                  array[resultIndex] = input[sourceIndex]
                  sourceIndex = reorderEytzinger(input, array: &array, sourceIndex: sourceIndex + 1, resultIndex: 2 * resultIndex + 1)
              }
              return sourceIndex
          }
      
          init() {
              let sortedArray: [Int] = (0..<arrayCount).map { _ in
                  .random(in: 0..<arrayCount)
              }.sorted()
              var eytzingerArray: [Int] = Array(repeating: 0, count: arrayCount + 1)
              _ = Self.reorderEytzinger(sortedArray, array: &eytzingerArray, sourceIndex: 0, resultIndex: 1)
              self.randomElements = (0..<searchCount).map { _ in
                  sortedArray.randomElement()!
              }
              self.eytzingerArray = eytzingerArray
          }
      
          @Test func searchEytzinger() throws {
              let span = eytzingerArray.span
              search(name: "Eytzinger", duration: .seconds(1)) {
                  for element in randomElements {
                      _ = binarySearchEytzinger(needle: element, haystack: span)
                  }
              }
          }
      }
    • 0:00 - Introduction et ordre du jour
    • L'optimisation du code pour les CPU à puce Apple est complexe en raison des couches d'abstraction entre le code source Swift et les instructions-machine, ainsi que des modes d'exécution désordonnés des instructions et de l'utilisation des caches mémoires par les CPU. Instruments aide les développeurs à naviguer dans cette complexité en facilitant l'analyse des performances et le profilage du système pour identifier une utilisation excessive du CPU. Utilisez les instruments Processor Trace et CPU Counters pour enregistrer les instructions, mesurer les coûts et analyser les goulots d'étranglement, ce qui conduit à un code plus efficace et de meilleures performances applicatives.

    • 2:28 - État d’esprit de performance
    • Lors de l'analyse de problèmes de performance, il est essentiel de garder l'esprit ouvert et de recueillir des données pour valider les hypothèses. Les ralentissements peuvent venir de plusieurs facteurs, comme des threads bloqués sur des ressources, une mauvaise utilisation des API ou des algorithmes inefficaces. Des outils comme la jauge de CPU intégrée de Xcode ainsi que les instruments System Trace et Hangs dans Instruments sont précieux pour identifier les habitudes d'utilisation CPU, les blocages et les problèmes de réactivité de l'interface. Avant de plonger dans les micro-optimisations, qui compliquent souvent la maintenance du code, il vaut mieux explorer d'autres approches. Ces alternatives incluent : éviter les calculs inutiles, différer les traitements via la concurrence, précalculer certaines valeurs, ou mettre en cache les états issus d'opérations coûteuses. Si ces stratégies sont épuisées, il devient alors nécessaire d'optimiser le code lié au CPU. Concentrez-vous sur le code ayant un fort impact sur l'expérience utilisateur, notamment le chemin critique des interactions. Il est recommandé d'optimiser de manière incrémentale, en mesurant les progrès via des tests automatisés et des métriques dans Xcode et Instruments.

    • 8:50 - Profileurs
    • Pour analyser les performances CPU de l'exemple de recherche binaire présenté, deux profileurs sont proposés dans Instruments : Time Profiler et CPU Profiler. Time Profiler échantillonne périodiquement l'activité CPU, mais peut subir des effets d'aliasing, déformant la représentation de l'activité réelle. CPU Profiler, quant à lui, échantillonne les CPU de façon indépendante en fonction de leur fréquence d'horloge, une méthode plus précise pour l'optimisation CPU. Dans cette analyse, CPU Profiler est lancé depuis le navigateur de test de Xcode, avec un enregistrement en mode différé dans Instruments pour limiter la surcharge. Les zones d'Instruments sont introduites : la vue chronologique, les pistes et les voies, et la vue détaillée qui présente les résultats du profilage. En examinant les pistes Points of Interest et Process, on repère la zone où les recherches binaires sont effectuées dans l'exemple d'application. L'arborescence des appels indique que les fonctions liées au protocole Collection consomment beaucoup de temps CPU. Une optimisation consiste à utiliser un type de conteneur plus efficace, tel que Span, pour éviter la surcharge des Array (sémantique copie sur écriture) et génériques.

    • 13:20 - Étendue
    • Span, introduit dans Swift 6.2, est une structure de données efficiente représentant une plage de mémoire contiguë. Utiliser Span comme type d'entrée/sortie pour la recherche binaire permet une amélioration de performance de 400 % sans changer l'algorithme. Ensuite, pour optimiser davantage les performances, l'instrument Processor Trace est utilisé afin d'analyser la surcharge de vérification des limites.

    • 14:05 - Processor Trace
    • Instruments 16.3 a introduit un nouvel instrument important appelé Processor Trace. Il permet de tracer toutes les instructions exécutées par le processus de votre app dans l'espace utilisateur sur Mac et iPad Pro avec puces M4 (et versions ultérieures), ou iPhone avec puces A18 (et versions ultérieures). Processor Trace nécessite l'activation de certains réglages spécifiques sur l'appareil. Il est particulièrement efficace pour des sessions de traçage courtes, car il peut générer une quantité importante de données. En enregistrant chaque décision de branchement, chaque nombre de cycles et l'heure actuelle, Instruments reconstruit le chemin d'exécution exact de l'app. Les données sont affichées sous forme de graphique de flamme, montrant la consommation de chaque appel de fonction. Contrairement aux graphiques de flamme traditionnels qui utilisent l'échantillonnage, le graphique de flamme de Processor Trace fournit une représentation exacte de la manière dont le CPU a exécuté le code. Cela vous permet d'identifier les goulots d'étranglement de performance avec une précision sans précédent. L'analyse des données de trace montre que la surcharge des métadonnées de protocole et l'incapacité à effectuer des comparaisons numériques provoquent d'importants ralentissements dans une fonction de recherche binaire spécifique. Pour remédier à cela, la fonction est spécialisée manuellement pour le type Int, ce qui améliore la performance d'environ 170 %. Cependant, une optimisation supplémentaire est nécessaire, car l'implémentation de la recherche binaire de l'app continue de ralentir l'ensemble.

    • 19:51 - Analyse des goulots d’étranglement
    • Les CPU à puce Apple exécutent les instructions en deux phases : Instruction Delivery (livraison des instructions) et Instruction Processing (traitement des instructions), qui sont canalisés pour permettre le parallélisme au niveau de l'instruction. Cela permet le traitement simultané de plusieurs opérations, maximisant l'efficacité. Cependant, des goulots d'étranglement peuvent survenir dans le pipeline, ce qui bloque certaines opérations et réduit le parallélisme. L'instrument CPU Counters aide à identifier ces goulots en comptant les événements dans chaque unité CPU. Il utilise des modes prédéfinis pour mesurer les performances du CPU et répartir les tâches par grandes catégories. En analysant les données échantillonnées, on peut repérer les instructions problématiques, comme les erreurs de prédiction de branchement, qui entraînent des cycles gaspillés et une dégradation des performances. Les CPU exécutent les instructions hors ordre en s'appuyant sur des prédicteurs de branchement pour améliorer les performances. Cependant, des branches aléatoires peuvent induire ces prédicteurs en erreur. Pour y remédier, le code est réécrit afin d'éviter les branches difficiles à prédire. Le résultat est une recherche binaire sans branche, environ deux fois plus rapide. L'optimisation de l'app se concentre ensuite sur les accès mémoire, car les CPU utilisent une hiérarchie de caches pour accélérer l'accès aux données. Le schéma d'accès de l'algorithme de recherche binaire était sous-optimal pour cette hiérarchie, entraînant de nombreuses erreurs de cache. En réorganisant les éléments du tableau selon une disposition dite Eytzinger, la localité de cache est améliorée. Cela permet de rendre la recherche binaire encore 200 % plus rapide. Malgré ces optimisations significatives, le code reste techniquement limité par le traitement des instructions. Cependant, la fonction de recherche a été accélérée d'environ 2 500 % grâce au profilage et à des micro-optimisations.

    • 31:33 - Récapitulatif
    • En mesurant d'abord les surcharges logicielles, puis en ciblant les goulots d'étranglement du CPU, la performance de l'app a été améliorée grâce à une approche attentive à l'architecture matérielle.

    • 32:13 - Étapes suivantes
    • Pour optimiser vos apps, utilisez Instruments pour collecter des données, effectuer des tests de performance, et analyser les résultats. Vous pouvez également regarder les sessions sur les performances de Swift, et lire le guide « Apple Silicon CPU Optimization » dans la documentation développeur. Posez vos questions ou envoyez vos retours sur les Forums des développeurs.

Developer Footer

  • Vidéos
  • WWDC25
  • Optimiser les performances du processeur avec Instruments
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • Apple Intelligence
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Downloads
    • Sample Code
    • Videos
    Open Menu Close Menu
    • Help Guides & Articles
    • Contact Us
    • Forums
    • Feedback & Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • Mini Apps Partner Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Read the latest news.
    Get the Apple Developer app.
    Copyright © 2026 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines