Génération de code natif

*Ce contenu est traduit en utilisant l'IA (Beta) et peut contenir des erreurs. Pour consulter cette page en anglais, clique ici.

Avec le support de Luau pour la génération de code natif, les scripts côté serveur dans votre expérience peuvent être compilés directement dans les instructions de code machine que les CPU exécutent, plutôt que le code binaire régulier sur lequel la VM Luau fonctionne.Cette fonction peut être utilisée pour améliorer la vitesse d'exécution de certains scripts sur le serveur, en particulier ceux qui ont beaucoup de calculs numériques sans utiliser trop de lourdes bibliothèques Luau ou d'appels d'API Roblox.

Activer la génération de code natif

Pour activer la génération de code natif pour un Script , ajoutez le commentaire --!native en haut :¹


--!natif
print("Hello from native code!")

Cela permet la génération de code natif pour toutes les fonctions dans le script et la portée de niveau supérieur, si elle est jugée rentable.Aucun changement supplémentaire n'est requis ; le comportement des scripts exécutés nativement est exactement le même qu'avant et seule la performance est différente.Toutes les fonctionnalités de la langue Luau et toutes les API Roblox restent prises en charge.

Alternativement, vous pouvez activer la génération de code natif pour une fonction individuelle en ajoutant l'attribut @native :


@native
local function f(x)
return (x + 1)
end
1 Dans le futur, certains scripts pourraient commencer à s'exécuter nativement s'il est déterminé qu'ils sont rentables, mais des commentaires manuellement placés --!native sont actuellement requis.

Meilleures pratiques

Les conseils suivants vous aideront à tirer le meilleur parti de la génération de code natif :

  • Il est préférable d'activer cette fonctionnalité à l'intérieur des scripts qui effectuent beaucoup de calcul directement à l'intérieur de Luau.Si vous avez beaucoup d'opérations mathématiques sur les tables et surtout les types buffer, le script peut être un bon candidat.

  • Seules les fonctions du script sont compilées nativement.Le code dans le domaine supérieur extérieur scope est souvent exécuté une seule fois et ne profite pas autant que les fonctions qui sont appelées plusieurs fois, notamment celles qui sont appelées à chaque cadre.

  • Il est recommandé de mesurer le temps qu'un script ou une fonction prend avec et sans compilation native pour juger quand il est préférable de l'utiliser.L'outil Profil de script peut mesurer les performances des fonctions afin de prendre des décisions éclairées.

  • Il peut être tentant de placer le commentaire --!native dans chaque script au cas où certains d'entre eux s'exécuteraient plus rapidement, mais la génération de code natif a quelques inconvénients :

    • Le temps de compilation du code est requis, ce qui peut augmenter le temps de démarrage des serveurs.
    • La mémoire supplémentaire est occupée pour stocker du code compilé nativement.
    • Il y a une limite sur le montant total autorisé de code compilé nativement dans une expérience.

Ces problèmes peuvent être résolus par une utilisation judicieuse de l'attribut @native.

Code à éviter

Bien que toutes les fonctionnalités se comportent de la même manière avec ou sans génération de code natif activée, certaines d'entre elles ne s'exécuteront pas nativement et pourraient provoquer une déoptimisation ou un retour à l'exécution interprétée.Ceux-ci incluent :

  • Utilisation des appels obsolètes getfenv() / setfenv().
  • Utilisation de diverses fonctions intégrées de Luau comme math.asin() avec des arguments non numériques.
  • Transmettre des paramètres mal saisis aux fonctions типированные, par exemple appeler foo(true) lorsque foo est déclaré comme function foo(arg: string) .N'oubliez pas d'utiliser toujours les annotations de type correct .

Lors de l'utilisation du profilateur de scripts, vous pouvez comparer le temps pris par une version régulière de la fonction versus celle compilée nativement.Si une fonction à l'intérieur d'un --!native script ou marquée avec @native n'apparaît pas nativement en exécution, un ou plusieurs facteurs de la liste ci-dessus peuvent déclencher une dé-optimisation.

Utiliser les annotations de type

La génération de code natif tente d'inférer le type le plus probable pour une variable donnée afin d'optimiser les chemins de code.Par exemple, il est supposé que a + b est effectué sur des nombres, ou qu'une table est accessible en t.X .Cependant, en raison de l'excès de charge de l'opérateur, a et b peuvent être des tables ou des types Vector3 ou t peuvent être un type de données Roblox.

Bien que la génération de code natif puisse prendre en charge n'importe quel taper, les prédictions erronées peuvent déclencher des vérifications inutiles, entraînant une exécution de code plus lente.

Pour résoudre certains problèmes communs, les annotations de type Luau sur les arguments de fonction sont vérifiées, mais il est spécialement recommandé d'annoter les arguments Vector3:


--!natif
-- « v » est supposé être une table ; la fonction fonctionne plus lentement en raison de vérifications de table
local function sumComponentsSlow(v)
return v.X + v.Y + v.Z
end
-- « v » est déclaré être un Vector3 ; le code spécialisé pour les vecteurs est généré
local function sumComponentsFast(v: Vector3)
return v.X + v.Y + v.Z
end

Outils de studio

Les outils de studio suivants sont pris en charge pour --!native les scripts et les fonctions @native.

Débogage

Le débogage général des scripts est pris en charge, mais les vues pour les locaux/les valeurs supérieures peuvent être incomplètes et manquer de variables du pilier d'appel qui s'exécute nativement.

Notez également que lors du débogage du code sélectionné pour la compilation native, le placement de points d'arrêt désactivera l'exécution native pour ces fonctions.

Profilateur de scripts

Dans le profilateur de scripts, les fonctions s'exécutant nativement affichent <native> à côté d'elles :

Example of native functions flagged in the Script Profiler

Si une fonction marquée ou à l'intérieur d'un script ne montre pas l'annotation , cette fonction peut ne pas être exécutée nativement en raison du placement du point d'arrêt , de l'utilisation du code désencouragé ou des annulations de type d'annotations .

Tas Luau

Dans le profilateur Luau heap, la mémoire prise par les fonctions natives s'affiche comme des éléments [native] dans le graphique.

Example of native memory usage flagged in the Luau Heap profiler

Analyse de la taille

Chaque script compilé nativement consomme de la mémoire.Lorsque la taille du code compilé atteint une limite prédéfinie, la compilation native s'arrête et le code restant est exécuté sans nativité.Cela rend essentiel de choisir soigneusement les scripts pour la compilation native.

Pour surveiller la taille du code natif des fonctions et des scripts individuels :

  1. Assurez-vous d'être dans vue du serveur à travers le bouton client/serveur bascule.
  2. Invokez debug.dumpcodesize() à partir de la barre de commande.

Dans la fenêtre Sortie, vous verrez le nombre total de scripts et de fonctions qui ont été compilés nativement jusqu'au point d'invocation, le volume de mémoire consommé par leur code natif et la limite de taille du code natif.Après le sommaire, vous verrez une table pour chaque script compilé nativement dans l'ordre décroissant de la taille du code.

Example of native code size displayed in the Output window.

Pour chaque script, la sortie affiche le nombre de fonctions compilées et la consommation de mémoire du code natif.Chaque fonction est ensuite listée dans l'ordre décroissant de la taille du code natif, avec des fonctions anonymes affichées comme [anonymous] et des scripts entiers affichés comme [top level].Dans la colonne finale, le pourcentage est calculé par rapport à la limite de taille du code natif.Notez que la taille du code natif des fonctions est signalée avec précision, mais la consommation de mémoire pour les scripts est arrondie à la plus proche taille de page.

Limites et dépannage

La compilation du code en instructions pour un CPU spécifique nécessite plus de mémoire de stockage.De plus, les optimisations pour les fonctions complexes peuvent prendre trop de temps à s'exécuter.Atteindre une limite interne signalera une erreur dans la fenêtre Sortie de Studio, y compris :

Fonction 'f' à la ligne 20 a dépassé la limite d'instruction de bloc de code unique

Cette erreur signifie qu'un seul bloc de code à l'intérieur d'une fonction a utilisé plus de 64K instructions.Cela peut être évité en simplifiant la fonction ou en la divisant en petites fonctions individuelles.

Fonction 'f' à la ligne 20 a dépassé la limite du bloc de code fonctionnel

Cette erreur signifie qu'une seule fonction contient plus de 32K blocs internes de code.Les blocs de code internes ne correspondent pas exactement aux blocs de flux de contrôle dans votre script, mais cette erreur peut être évitée en simplifiant le flux de contrôle dans la fonction ou en le divisant en plusieurs fonctions plus petites.

Fonction 'f' à la ligne 200 a dépassé la limite d'instruction du module total

Cette erreur signifie que, en tout, la fonction a atteint une limite de 1 million d'instructions pour l'ensemble du script.Dans certains cas, la fonction signalée elle-même peut avoir beaucoup d'instructions, ou la limite a peut-être été atteinte par des fonctions plus tôt dans le script.Pour éviter ce problème, il est recommandé de déplacer des fonctions particulièrement grandes dans un script non natif séparé ou d'utiliser @native sur les autres fonctions.Vous pouvez également essayer de marquer ce script séparé avec --!native , mais 1 million d'instructions prend beaucoup de mémoire et vous pouvez dépasser la limite de mémoire.

*La fonction 'f' à la ligne 20 a rencontré une échec de baisse interne *(ou) Erreur interne : génération de code natif échouée (abaissement d'assemblage)

Parfois, une fonction contient des bits de code complexes que le compilateur de code natif ne peut pas contrôleuractuellement.Pour éviter cette erreur, inspectez les expressions complexes dans le code et divisez-les ou simplifiez-les, mais envisagez également d'ouvrir un rapport de bogue avec un exemple de code qui a échoué pour cette raison.

Limite d'allocation de mémoire atteinte pour la génération de code natif

Cette erreur signifie que la limite de mémoire globale pour les données de code natif a été atteinte.Pour éviter cela, essayez de supprimer --!native des scripts plus gourmands en mémoire, permettant à plus de scripts plus petits de s'insérer sous la limite.Alternativement, déplacez les fonctions grandes ou peu appelées vers un module non natif séparé.